mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-02-01 03:19:23 +00:00
Application settings
This commit is contained in:
parent
f39a3c4a15
commit
57534e2c44
27 changed files with 1715 additions and 108 deletions
|
|
@ -5,7 +5,7 @@ project(Linphone VERSION 6.0 LANGUAGES CXX)
|
|||
################################################################
|
||||
# PACKAGES
|
||||
################################################################
|
||||
set(LINPHONE_PACKAGES LinphoneCxx BCToolbox)
|
||||
set(LINPHONE_PACKAGES Mediastreamer2 LinphoneCxx BCToolbox LibLinphone)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules")
|
||||
foreach(PACKAGE ${LINPHONE_PACKAGES})
|
||||
message(STATUS "Trying to find ${PACKAGE}")
|
||||
|
|
@ -17,7 +17,9 @@ endforeach()
|
|||
|
||||
|
||||
set(TARGET_NAME Linphone)
|
||||
set(APP_TARGETS ${LinphoneCxx_TARGET})
|
||||
set(APP_TARGETS ${LinphoneCxx_TARGET}
|
||||
${Mediastreamer2_TARGET}#MediastreamerUtils
|
||||
${LibLinphone_TARGET})#MediastreamerUtils
|
||||
|
||||
set(QT_DEFAULT_MAJOR_VERSION 6)
|
||||
set(QT_PACKAGES Core Quick Qml Widgets Svg Multimedia Test)# Search Core at first for initialize Qt scripts for next find_packages.
|
||||
|
|
|
|||
|
|
@ -41,23 +41,28 @@ QSharedPointer<Settings> Settings::create() {
|
|||
Settings::Settings(QObject *parent) : QObject(parent) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
mSettingsModel = Utils::makeQObject_ptr<SettingsModel>();
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
for (auto &device : core->getExtendedAudioDevices()) {
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityRecord)) {
|
||||
mInputAudioDevices.append(Utils::coreStringToAppString(device->getId()));
|
||||
// mInputAudioDevices.append(createDeviceVariant(Utils::coreStringToAppString(device->getId()),
|
||||
// Utils::coreStringToAppString(device->getDeviceName())));
|
||||
}
|
||||
if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityPlay)) {
|
||||
mOutputAudioDevices.append(Utils::coreStringToAppString(device->getId()));
|
||||
// mOutputAudioDevices.append(createDeviceVariant(Utils::coreStringToAppString(device->getId()),
|
||||
// Utils::coreStringToAppString(device->getDeviceName())));
|
||||
}
|
||||
}
|
||||
for (auto &device : core->getVideoDevicesList()) {
|
||||
mVideoDevices.append(Utils::coreStringToAppString(device));
|
||||
}
|
||||
|
||||
// Security
|
||||
mVfsEnabled = mSettingsModel->getVfsEnabled();
|
||||
|
||||
// Call
|
||||
mVideoEnabled = mSettingsModel->getVideoEnabled();
|
||||
mEchoCancellationEnabled = mSettingsModel->getEchoCancellationEnabled();
|
||||
mAutomaticallyRecordCallsEnabled = mSettingsModel->getAutomaticallyRecordCallsEnabled();
|
||||
|
||||
// Audio
|
||||
mCaptureDevices = mSettingsModel->getCaptureDevices();
|
||||
mPlaybackDevices = mSettingsModel->getPlaybackDevices();
|
||||
mCaptureDevice = mSettingsModel->getCaptureDevice();
|
||||
mPlaybackDevice = mSettingsModel->getPlaybackDevice();
|
||||
|
||||
mCaptureGain = mSettingsModel->getCaptureGain();
|
||||
mPlaybackGain = mSettingsModel->getPlaybackGain();
|
||||
|
||||
// Video
|
||||
mVideoDevice = mSettingsModel->getVideoDevice();
|
||||
mVideoDevices = mSettingsModel->getVideoDevices();
|
||||
|
||||
}
|
||||
|
||||
Settings::~Settings() {
|
||||
|
|
@ -67,13 +72,162 @@ void Settings::setSelf(QSharedPointer<Settings> me) {
|
|||
mustBeInLinphoneThread(getClassName());
|
||||
mSettingsModelConnection = QSharedPointer<SafeConnection<Settings, SettingsModel>>(
|
||||
new SafeConnection<Settings, SettingsModel>(me, mSettingsModel), &QObject::deleteLater);
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::lSetVideoDevice, [this](const QString &id) {
|
||||
|
||||
// VFS
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setVfsEnabled, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, id]() { mSettingsModel->setVideoDevice(Utils::appStringToCoreString(id)); });
|
||||
[this, enabled]() { mSettingsModel->setVfsEnabled(enabled); }
|
||||
);
|
||||
});
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::videoDeviceChanged, [this](const std::string &id) {
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::vfsEnabledChanged, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, enabled]() {
|
||||
mVfsEnabled = enabled;
|
||||
emit vfsEnabledChanged();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Video Calls
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setVideoEnabled, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, id = Utils::coreStringToAppString(id)]() { setCurrentVideoDevice(id); });
|
||||
[this, enabled]() { mSettingsModel->setVideoEnabled(enabled); }
|
||||
);
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::videoEnabledChanged, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, enabled]() {
|
||||
mVideoEnabled = enabled;
|
||||
emit videoEnabledChanged();
|
||||
});
|
||||
});
|
||||
|
||||
// Echo cancelling
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setEchoCancellationEnabled, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, enabled]() { mSettingsModel->setEchoCancellationEnabled(enabled); }
|
||||
);
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::echoCancellationEnabledChanged, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, enabled]() {
|
||||
mEchoCancellationEnabled = enabled;
|
||||
emit echoCancellationEnabledChanged();
|
||||
});
|
||||
});
|
||||
|
||||
// Auto recording
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setAutomaticallyRecordCallsEnabled, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, enabled]() { mSettingsModel->setAutomaticallyRecordCallsEnabled(enabled); }
|
||||
);
|
||||
});
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::automaticallyRecordCallsEnabledChanged, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, enabled]() {
|
||||
mAutomaticallyRecordCallsEnabled = enabled;
|
||||
emit automaticallyRecordCallsEnabledChanged();
|
||||
});
|
||||
});
|
||||
|
||||
// Audio device(s)
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setCaptureDevice, [this](const QString id) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, id]() { mSettingsModel->setCaptureDevice(id); });
|
||||
});
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::captureDeviceChanged, [this](const QString device) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, device]() {
|
||||
mCaptureDevice = device;
|
||||
emit captureDeviceChanged(device);
|
||||
});
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setPlaybackDevice, [this](const QString id) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, id]() { mSettingsModel->setPlaybackDevice(id); });
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::playbackDeviceChanged, [this](const QString device) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, device]() {
|
||||
mPlaybackDevice = device;
|
||||
emit playbackDeviceChanged(device);
|
||||
});
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setPlaybackGain, [this](const float value) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, value]() { mSettingsModel->setPlaybackGain(value); });
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::playbackGainChanged, [this](const float value) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, value]() {
|
||||
mPlaybackGain = value;
|
||||
emit playbackGainChanged(value);
|
||||
});
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setCaptureGain, [this](const float value) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, value]() { mSettingsModel->setCaptureGain(value); });
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::captureGainChanged, [this](const float value) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, value]() {
|
||||
mCaptureGain = value;
|
||||
emit captureGainChanged(value);
|
||||
});
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::micVolumeChanged, [this](const float value) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, value]() {
|
||||
emit micVolumeChanged(value);
|
||||
});
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::captureDevicesChanged, [this](const QStringList devices) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, devices]() {
|
||||
mCaptureDevices = devices;
|
||||
emit captureDevicesChanged(devices);
|
||||
});
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::playbackDevicesChanged, [this](const QStringList devices) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, devices]() {
|
||||
mPlaybackDevices = devices;
|
||||
emit playbackDevicesChanged(devices);
|
||||
});
|
||||
});
|
||||
|
||||
// Video device(s)
|
||||
mSettingsModelConnection->makeConnectToCore(&Settings::setVideoDevice, [this](const QString id) {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this, id]() { mSettingsModel->setVideoDevice(id); });
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::videoDeviceChanged, [this](const QString device) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, device]() {
|
||||
mVideoDevice = device;
|
||||
emit videoDeviceChanged();
|
||||
});
|
||||
});
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::videoDevicesChanged, [this](const QStringList devices) {
|
||||
mSettingsModelConnection->invokeToCore(
|
||||
[this, devices]() {
|
||||
mVideoDevices = devices;
|
||||
emit videoDevicesChanged();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -89,33 +243,44 @@ QString Settings::getConfigPath(const QCommandLineParser &parser) {
|
|||
return configPath;
|
||||
}
|
||||
|
||||
QStringList Settings::getInputAudioDevicesList() const {
|
||||
return mInputAudioDevices;
|
||||
QStringList Settings::getCaptureDevices() const {
|
||||
return mCaptureDevices;
|
||||
}
|
||||
|
||||
QStringList Settings::getOutputAudioDevicesList() const {
|
||||
return mOutputAudioDevices;
|
||||
QStringList Settings::getPlaybackDevices() const {
|
||||
return mPlaybackDevices;
|
||||
}
|
||||
|
||||
QStringList Settings::getVideoDevicesList() const {
|
||||
QStringList Settings::getVideoDevices() const {
|
||||
return mVideoDevices;
|
||||
}
|
||||
|
||||
void Settings::setCurrentVideoDevice(const QString &id) {
|
||||
if (mCurrentVideoDeviceId != id) {
|
||||
mCurrentVideoDeviceId = id;
|
||||
emit videoDeviceChanged();
|
||||
}
|
||||
bool Settings::getCaptureGraphRunning() {
|
||||
return mCaptureGraphRunning;
|
||||
}
|
||||
|
||||
int Settings::getCurrentVideoDeviceIndex() {
|
||||
auto found = std::find_if(mVideoDevices.begin(), mVideoDevices.end(),
|
||||
[this](const QString &device) { return mCurrentVideoDeviceId == device; });
|
||||
if (found != mVideoDevices.end()) {
|
||||
auto index = std::distance(mVideoDevices.begin(), found);
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
float Settings::getCaptureGain() const {
|
||||
return mCaptureGain;
|
||||
}
|
||||
|
||||
float Settings::getPlaybackGain() const {
|
||||
return mPlaybackGain;
|
||||
}
|
||||
|
||||
QString Settings::getRingerDevice() const {
|
||||
return mRingerDevice;
|
||||
}
|
||||
|
||||
QString Settings::getCaptureDevice() const {
|
||||
return mCaptureDevice;
|
||||
}
|
||||
|
||||
QString Settings::getPlaybackDevice() const {
|
||||
return mPlaybackDevice;
|
||||
}
|
||||
|
||||
int Settings::getEchoCancellationCalibration() const {
|
||||
return mEchoCancellationCalibration;
|
||||
}
|
||||
|
||||
bool Settings::getFirstLaunch() const {
|
||||
|
|
@ -129,4 +294,28 @@ void Settings::setFirstLaunch(bool first) {
|
|||
mAppSettings.setValue("firstLaunch", (int)first);
|
||||
mAppSettings.sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::startEchoCancellerCalibration() {
|
||||
mSettingsModelConnection->invokeToModel([this]() {
|
||||
mSettingsModel->startEchoCancellerCalibration();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Settings::accessCallSettings() {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this]() { mSettingsModel->accessCallSettings(); }
|
||||
);
|
||||
}
|
||||
void Settings::closeCallSettings() {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this]() { mSettingsModel->closeCallSettings(); }
|
||||
);
|
||||
}
|
||||
|
||||
void Settings::updateMicVolume() const {
|
||||
mSettingsModelConnection->invokeToModel(
|
||||
[this]() { mSettingsModel->getMicVolume(); }
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,10 +31,33 @@
|
|||
|
||||
class Settings : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QStringList inputAudioDevicesList READ getInputAudioDevicesList NOTIFY inputAudioDeviceChanged)
|
||||
Q_PROPERTY(QStringList outputAudioDevicesList READ getOutputAudioDevicesList NOTIFY outputAudioDeviceChanged)
|
||||
Q_PROPERTY(QStringList videoDevicesList READ getVideoDevicesList NOTIFY videoDeviceChanged)
|
||||
Q_PROPERTY(int currentVideoDeviceIndex READ getCurrentVideoDeviceIndex NOTIFY videoDeviceChanged)
|
||||
|
||||
// Security
|
||||
Q_PROPERTY(bool vfsEnabled READ getVfsEnabled WRITE setVfsEnabled NOTIFY vfsEnabledChanged)
|
||||
|
||||
// Call
|
||||
Q_PROPERTY(bool videoEnabled READ getVideoEnabled WRITE setVideoEnabled NOTIFY videoEnabledChanged)
|
||||
Q_PROPERTY(bool echoCancellationEnabled READ getEchoCancellationEnabled WRITE setEchoCancellationEnabled NOTIFY echoCancellationEnabledChanged)
|
||||
Q_PROPERTY(int echoCancellationCalibration READ getEchoCancellationCalibration NOTIFY echoCancellationCalibrationChanged)
|
||||
Q_PROPERTY(bool automaticallyRecordCallsEnabled READ getAutomaticallyRecordCallsEnabled WRITE setAutomaticallyRecordCallsEnabled NOTIFY automaticallyRecordCallsEnabledChanged)
|
||||
|
||||
Q_PROPERTY(bool captureGraphRunning READ getCaptureGraphRunning NOTIFY captureGraphRunningChanged)
|
||||
|
||||
Q_PROPERTY(QStringList captureDevices READ getCaptureDevices NOTIFY captureDevicesChanged)
|
||||
Q_PROPERTY(QStringList playbackDevices READ getPlaybackDevices NOTIFY playbackDevicesChanged)
|
||||
|
||||
Q_PROPERTY(float playbackGain READ getPlaybackGain WRITE setPlaybackGain NOTIFY playbackGainChanged)
|
||||
Q_PROPERTY(float captureGain READ getCaptureGain WRITE setCaptureGain NOTIFY captureGainChanged)
|
||||
|
||||
Q_PROPERTY(QString captureDevice READ getCaptureDevice WRITE setCaptureDevice NOTIFY captureDeviceChanged)
|
||||
Q_PROPERTY(QString playbackDevice READ getPlaybackDevice WRITE setPlaybackDevice NOTIFY playbackDeviceChanged)
|
||||
Q_PROPERTY(QString ringerDevice READ getRingerDevice WRITE setRingerDevice NOTIFY ringerDeviceChanged)
|
||||
|
||||
Q_PROPERTY(QStringList videoDevices READ getVideoDevices NOTIFY videoDevicesChanged)
|
||||
Q_PROPERTY(QString videoDevice READ getVideoDevice WRITE setVideoDevice NOTIFY videoDeviceChanged)
|
||||
|
||||
Q_PROPERTY(float micVolume MEMBER _dummy_int NOTIFY micVolumeChanged)
|
||||
|
||||
public:
|
||||
static QSharedPointer<Settings> create();
|
||||
Settings(QObject *parent = Q_NULLPTR);
|
||||
|
|
@ -44,33 +67,116 @@ public:
|
|||
|
||||
QString getConfigPath(const QCommandLineParser &parser = QCommandLineParser());
|
||||
|
||||
QStringList getInputAudioDevicesList() const;
|
||||
|
||||
QStringList getOutputAudioDevicesList() const;
|
||||
|
||||
QStringList getVideoDevicesList() const;
|
||||
|
||||
void setCurrentVideoDevice(const QString &id);
|
||||
int getCurrentVideoDeviceIndex();
|
||||
|
||||
Q_INVOKABLE void setFirstLaunch(bool first);
|
||||
Q_INVOKABLE bool getFirstLaunch() const;
|
||||
|
||||
// Security. --------------------------------------------------------------------
|
||||
bool getVfsEnabled() { return mVfsEnabled; }
|
||||
|
||||
// Call. --------------------------------------------------------------------
|
||||
|
||||
bool getVideoEnabled() { return mVideoEnabled; }
|
||||
bool getEchoCancellationEnabled() { return mEchoCancellationEnabled; }
|
||||
bool getAutomaticallyRecordCallsEnabled() { return mAutomaticallyRecordCallsEnabled; }
|
||||
|
||||
float getPlaybackGain() const;
|
||||
|
||||
float getCaptureGain() const;
|
||||
|
||||
QStringList getCaptureDevices () const;
|
||||
QStringList getPlaybackDevices () const;
|
||||
|
||||
QString getCaptureDevice () const;
|
||||
|
||||
QString getPlaybackDevice () const;
|
||||
|
||||
QString getRingerDevice () const;
|
||||
|
||||
QString getVideoDevice() { return mVideoDevice; }
|
||||
QStringList getVideoDevices() const;
|
||||
|
||||
bool getCaptureGraphRunning();
|
||||
|
||||
Q_INVOKABLE void startEchoCancellerCalibration();
|
||||
int getEchoCancellationCalibration() const;
|
||||
|
||||
Q_INVOKABLE void accessCallSettings();
|
||||
Q_INVOKABLE void closeCallSettings();
|
||||
Q_INVOKABLE void updateMicVolume() const;
|
||||
|
||||
signals:
|
||||
void inputAudioDeviceChanged(const QString &id);
|
||||
void outputAudioDeviceChanged(const QString &id);
|
||||
void videoDeviceChanged();
|
||||
|
||||
// Security
|
||||
void setVfsEnabled(const bool enabled);
|
||||
void vfsEnabledChanged();
|
||||
|
||||
// Call
|
||||
void setVideoEnabled(const bool enabled);
|
||||
void videoEnabledChanged();
|
||||
|
||||
void setEchoCancellationEnabled(const bool enabled);
|
||||
void echoCancellationEnabledChanged();
|
||||
|
||||
void setAutomaticallyRecordCallsEnabled(const bool enabled);
|
||||
void automaticallyRecordCallsEnabledChanged();
|
||||
|
||||
void captureGraphRunningChanged(bool running);
|
||||
|
||||
void playbackGainChanged(float gain);
|
||||
void captureGainChanged(float gain);
|
||||
|
||||
void captureDevicesChanged (const QStringList &devices);
|
||||
void playbackDevicesChanged (const QStringList &devices);
|
||||
|
||||
void setCaptureDevice (const QString &device);
|
||||
void captureDeviceChanged (const QString &device);
|
||||
|
||||
void setPlaybackDevice (const QString &device);
|
||||
void playbackDeviceChanged (const QString &device);
|
||||
void ringerDeviceChanged (const QString &device);
|
||||
|
||||
void setVideoDevice(const QString &device);
|
||||
void videoDeviceChanged();
|
||||
void videoDevicesChanged();
|
||||
|
||||
void setCaptureGain(float gain);
|
||||
void setPlaybackGain(float gain);
|
||||
void setRingerDevice (const QString &device);
|
||||
|
||||
void echoCancellationCalibrationChanged();
|
||||
void micVolumeChanged(float volume);
|
||||
|
||||
void lSetInputAudioDevice(const QString &device);
|
||||
void lSetOutputAudioDevice(const QString &device);
|
||||
void lSetVideoDevice(const QString &device);
|
||||
|
||||
private:
|
||||
std::shared_ptr<SettingsModel> mSettingsModel;
|
||||
QStringList mInputAudioDevices;
|
||||
QString mCurrentVideoDeviceId;
|
||||
QStringList mOutputAudioDevices;
|
||||
|
||||
// Dummy properties (for properties that use values from core received throuh signals)
|
||||
int _dummy_int = 0;
|
||||
|
||||
// Security
|
||||
bool mVfsEnabled;
|
||||
|
||||
// Call
|
||||
bool mVideoEnabled;
|
||||
bool mEchoCancellationEnabled;
|
||||
bool mAutomaticallyRecordCallsEnabled;
|
||||
|
||||
// Audio
|
||||
QStringList mCaptureDevices;
|
||||
QStringList mPlaybackDevices;
|
||||
QString mCaptureDevice;
|
||||
QString mPlaybackDevice;
|
||||
QString mRingerDevice;
|
||||
|
||||
// Video
|
||||
QStringList mVideoDevices;
|
||||
QString mVideoDevice;
|
||||
|
||||
bool mCaptureGraphRunning;
|
||||
float mCaptureGain;
|
||||
float mPlaybackGain;
|
||||
int mEchoCancellationCalibration;
|
||||
|
||||
QSettings mAppSettings;
|
||||
QSharedPointer<SafeConnection<Settings, SettingsModel>> mSettingsModelConnection;
|
||||
|
||||
|
|
|
|||
4
Linphone/data/image/switch-off.svg
Normal file
4
Linphone/data/image/switch-off.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="32" height="20" viewBox="0 0 32 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="32" height="20" rx="10" fill="#9AABB5"/>
|
||||
<circle cx="10" cy="10" r="6" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 202 B |
4
Linphone/data/image/switch-on.svg
Normal file
4
Linphone/data/image/switch-on.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="32" height="20" viewBox="0 0 32 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="32" height="20" rx="10" fill="#4FAE80"/>
|
||||
<circle cx="22" cy="10" r="6" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 202 B |
|
|
@ -28,6 +28,8 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
model/search/MagicSearchModel.cpp
|
||||
|
||||
model/setting/SettingsModel.cpp
|
||||
model/setting/MediastreamerUtils.cpp
|
||||
|
||||
|
||||
model/tool/ToolModel.cpp
|
||||
|
||||
|
|
|
|||
203
Linphone/model/setting/MediastreamerUtils.cpp
Normal file
203
Linphone/model/setting/MediastreamerUtils.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* 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 <linphone/linphonecore.h>
|
||||
#include <mediastreamer2/msvolume.h>
|
||||
#include <mediastreamer2/mssndcard.h>
|
||||
#include <mediastreamer2/msticker.h>
|
||||
#include <model/core/CoreModel.hpp>
|
||||
#include "MediastreamerUtils.hpp"
|
||||
|
||||
#include <qlogging.h>
|
||||
|
||||
using namespace MediastreamerUtils;
|
||||
|
||||
SimpleCaptureGraph::SimpleCaptureGraph(const std::string &capture, const std::string &playback)
|
||||
: captureCardId(capture), playbackCardId(playback)
|
||||
{
|
||||
LinphoneCore *ccore = CoreModel::getInstance()->getCore()->cPtr();
|
||||
msFactory = linphone_core_get_ms_factory(ccore);
|
||||
|
||||
playbackCard = ms_snd_card_manager_get_card(ms_factory_get_snd_card_manager(msFactory), playbackCardId.c_str());
|
||||
if (!playbackCard)
|
||||
qWarning("Cannot get playback card from MSFactory with : %s", playbackCardId.c_str());
|
||||
captureCard = ms_snd_card_manager_get_card(ms_factory_get_snd_card_manager(msFactory), captureCardId.c_str());
|
||||
if (!captureCard)
|
||||
qWarning("Cannot get capture card from MSFactory with : %s", captureCardId.c_str());
|
||||
|
||||
if(playbackCard && captureCard)// Assure to initialize when playback and capture are available
|
||||
init();
|
||||
}
|
||||
|
||||
SimpleCaptureGraph::~SimpleCaptureGraph()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
static void device_notify_cb(void *user_data, MSFilter *f, unsigned int event, void *eventdata) {
|
||||
if (event == MS_FILTER_OUTPUT_FMT_CHANGED) {
|
||||
SimpleCaptureGraph * graph = (SimpleCaptureGraph *)user_data;
|
||||
int captureRate, playbackRate, captureChannels, playbackChannels;
|
||||
ms_filter_call_method(graph->audioCapture,MS_FILTER_GET_SAMPLE_RATE,&captureRate);
|
||||
ms_filter_call_method(graph->audioSink,MS_FILTER_GET_SAMPLE_RATE,&playbackRate);
|
||||
ms_filter_call_method(graph->audioCapture,MS_FILTER_GET_NCHANNELS,&captureChannels);
|
||||
ms_filter_call_method(graph->audioSink,MS_FILTER_GET_NCHANNELS,&playbackChannels);
|
||||
|
||||
ms_filter_call_method(graph->resamplerFilter,MS_FILTER_SET_SAMPLE_RATE,&captureRate);
|
||||
ms_filter_call_method(graph->resamplerFilter,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&playbackRate);
|
||||
ms_filter_call_method(graph->resamplerFilter,MS_FILTER_SET_NCHANNELS,&captureChannels);
|
||||
ms_filter_call_method(graph->resamplerFilter,MS_FILTER_SET_OUTPUT_NCHANNELS,&playbackChannels);
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleCaptureGraph::init() {
|
||||
if (!audioCapture) {
|
||||
audioCapture = ms_snd_card_create_reader(captureCard);
|
||||
ms_filter_add_notify_callback(audioCapture, device_notify_cb,this,FALSE);
|
||||
}
|
||||
if (!audioSink) {
|
||||
audioSink = ms_snd_card_create_writer(playbackCard);
|
||||
ms_filter_add_notify_callback(audioSink, device_notify_cb,this,FALSE);
|
||||
}
|
||||
if (!captureVolumeFilter) {
|
||||
captureVolumeFilter = ms_factory_create_filter(msFactory, MS_VOLUME_ID);
|
||||
}
|
||||
if (!playbackVolumeFilter) {
|
||||
playbackVolumeFilter = ms_factory_create_filter(msFactory, MS_VOLUME_ID);
|
||||
}
|
||||
if(!resamplerFilter)
|
||||
resamplerFilter = ms_factory_create_filter(msFactory, MS_RESAMPLE_ID);
|
||||
int captureRate, playbackRate, captureChannels, playbackChannels;
|
||||
ms_filter_call_method(audioCapture,MS_FILTER_GET_SAMPLE_RATE,&captureRate);
|
||||
ms_filter_call_method(audioSink,MS_FILTER_GET_SAMPLE_RATE,&playbackRate);
|
||||
ms_filter_call_method(audioCapture,MS_FILTER_GET_NCHANNELS,&captureChannels);
|
||||
ms_filter_call_method(audioSink,MS_FILTER_GET_NCHANNELS,&playbackChannels);
|
||||
|
||||
ms_filter_call_method(resamplerFilter,MS_FILTER_SET_SAMPLE_RATE,&captureRate);
|
||||
ms_filter_call_method(resamplerFilter,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&playbackRate);
|
||||
ms_filter_call_method(resamplerFilter,MS_FILTER_SET_NCHANNELS,&captureChannels);
|
||||
ms_filter_call_method(resamplerFilter,MS_FILTER_SET_OUTPUT_NCHANNELS,&playbackChannels);
|
||||
|
||||
ms_filter_link(audioCapture, 0, captureVolumeFilter, 0);
|
||||
ms_filter_link(captureVolumeFilter, 0, resamplerFilter, 0);
|
||||
ms_filter_link(resamplerFilter, 0, playbackVolumeFilter, 0);
|
||||
ms_filter_link(playbackVolumeFilter, 0, audioSink, 0);
|
||||
|
||||
//Mute playback
|
||||
float muteGain = 0.0f;
|
||||
ms_filter_call_method(playbackVolumeFilter, static_cast<unsigned int>(MS_VOLUME_SET_GAIN), &muteGain);
|
||||
ticker = ms_ticker_new();
|
||||
running = false;
|
||||
|
||||
}
|
||||
|
||||
void SimpleCaptureGraph::start() {
|
||||
if (!running && audioCapture) {
|
||||
running = true;
|
||||
ms_ticker_attach(ticker, audioCapture);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleCaptureGraph::stop() {
|
||||
if (running && audioCapture){
|
||||
ms_ticker_detach(ticker, audioCapture);
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleCaptureGraph::destroy() {
|
||||
if (running) {
|
||||
stop();
|
||||
}
|
||||
|
||||
if (audioSink)
|
||||
ms_filter_unlink(playbackVolumeFilter, 0, audioSink, 0);
|
||||
if (captureVolumeFilter && resamplerFilter)
|
||||
ms_filter_unlink(captureVolumeFilter, 0, resamplerFilter, 0);
|
||||
if (resamplerFilter && playbackVolumeFilter)
|
||||
ms_filter_unlink(resamplerFilter, 0, playbackVolumeFilter, 0);
|
||||
if (audioCapture)
|
||||
ms_filter_unlink(audioCapture, 0, captureVolumeFilter, 0);
|
||||
if (playbackVolumeFilter)
|
||||
ms_filter_destroy(playbackVolumeFilter);
|
||||
if (captureVolumeFilter)
|
||||
ms_filter_destroy(captureVolumeFilter);
|
||||
if (resamplerFilter)
|
||||
ms_filter_destroy(resamplerFilter);
|
||||
if (audioSink)
|
||||
ms_filter_destroy(audioSink);
|
||||
if (audioCapture)
|
||||
ms_filter_destroy(audioCapture);
|
||||
if (ticker) {
|
||||
ms_ticker_destroy(ticker);// Destroy ticker at the end to avoid conflicts between attached filters
|
||||
}
|
||||
ticker = nullptr;
|
||||
playbackVolumeFilter = nullptr;
|
||||
captureVolumeFilter = nullptr;
|
||||
resamplerFilter = nullptr;
|
||||
audioSink = nullptr;
|
||||
audioCapture = nullptr;
|
||||
}
|
||||
|
||||
float SimpleCaptureGraph::getCaptureGain() {
|
||||
float gain = 0.0f;
|
||||
|
||||
if (isRunning() && audioCapture) {
|
||||
ms_filter_call_method(audioCapture, MS_AUDIO_CAPTURE_GET_VOLUME_GAIN, &gain);
|
||||
}
|
||||
return gain;
|
||||
}
|
||||
|
||||
void SimpleCaptureGraph::setCaptureGain(float gain) {
|
||||
if (isRunning() && audioCapture) {
|
||||
ms_filter_call_method(audioCapture, MS_AUDIO_CAPTURE_SET_VOLUME_GAIN, &gain);
|
||||
}
|
||||
}
|
||||
|
||||
float SimpleCaptureGraph::getPlaybackGain() {
|
||||
float gain = 0.0f;
|
||||
if (isRunning() && audioSink) {
|
||||
ms_filter_call_method(audioSink, MS_AUDIO_PLAYBACK_GET_VOLUME_GAIN, &gain);
|
||||
}
|
||||
return gain;
|
||||
}
|
||||
|
||||
void SimpleCaptureGraph::setPlaybackGain(float gain) {
|
||||
if (isRunning() && audioSink) {
|
||||
ms_filter_call_method(audioSink, MS_AUDIO_PLAYBACK_SET_VOLUME_GAIN, &gain);
|
||||
}
|
||||
}
|
||||
|
||||
float SimpleCaptureGraph::getCaptureVolume() {
|
||||
float vol = 0;
|
||||
|
||||
if (captureVolumeFilter) {
|
||||
ms_filter_call_method(captureVolumeFilter, MS_VOLUME_GET, &vol);
|
||||
vol = MediastreamerUtils::dbToLinear(vol);
|
||||
}
|
||||
return vol;
|
||||
}
|
||||
|
||||
float MediastreamerUtils::linearToDb(float volume) {
|
||||
if (qFuzzyIsNull(volume)) {
|
||||
return MS_VOLUME_DB_LOWEST;
|
||||
}
|
||||
return static_cast<float>(10.0 * log10(volume));
|
||||
}
|
||||
99
Linphone/model/setting/MediastreamerUtils.hpp
Normal file
99
Linphone/model/setting/MediastreamerUtils.hpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTREAMER_UTILS_H_
|
||||
#define MEDIASTREAMER_UTILS_H_
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
struct _MSSndCard;
|
||||
struct _MSFilter;
|
||||
struct _MSTicker;
|
||||
struct _MSFactory;
|
||||
|
||||
namespace MediastreamerUtils {
|
||||
|
||||
inline float computeVu (float volume) {
|
||||
constexpr float VuMin = -20.f;
|
||||
constexpr float VuMax = 4.f;
|
||||
|
||||
if (volume < VuMin)
|
||||
return 0.f;
|
||||
if (volume > VuMax)
|
||||
return 1.f;
|
||||
|
||||
return (volume - VuMin) / (VuMax - VuMin);
|
||||
}
|
||||
|
||||
inline float dbToLinear(float volume) {
|
||||
return static_cast<float>(pow(10.0, volume / 10.0));
|
||||
}
|
||||
|
||||
float linearToDb(float volume);
|
||||
|
||||
//Simple mediastreamer audio capture graph
|
||||
//Used to get current microphone volume in audio settings
|
||||
class SimpleCaptureGraph {
|
||||
public:
|
||||
SimpleCaptureGraph(const std::string &captureCardId, const std::string &playbackCardId);
|
||||
~SimpleCaptureGraph();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
float getCaptureVolume();
|
||||
|
||||
float getCaptureGain();
|
||||
float getPlaybackGain();
|
||||
void setCaptureGain(float volume);
|
||||
void setPlaybackGain(float volume);
|
||||
|
||||
bool isRunning() const {
|
||||
return running;
|
||||
}
|
||||
|
||||
void init();
|
||||
void destroy();
|
||||
|
||||
bool running = false;
|
||||
|
||||
std::string captureCardId;
|
||||
std::string playbackCardId;
|
||||
|
||||
_MSFilter *audioSink = nullptr;
|
||||
_MSFilter *audioCapture = nullptr;
|
||||
_MSFilter *captureVolumeFilter = nullptr;
|
||||
_MSFilter *playbackVolumeFilter = nullptr;
|
||||
_MSFilter *resamplerFilter = nullptr;
|
||||
_MSTicker *ticker = nullptr;
|
||||
_MSSndCard *playbackCard = nullptr;
|
||||
_MSSndCard *captureCard = nullptr;
|
||||
_MSFactory *msFactory = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ifndef MEDIASTREAMER_UTILS_H_
|
||||
|
|
@ -20,15 +20,21 @@
|
|||
|
||||
#include "SettingsModel.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(SettingsModel)
|
||||
|
||||
using namespace std;
|
||||
|
||||
const std::string SettingsModel::UiSection("ui");
|
||||
|
||||
SettingsModel::SettingsModel(QObject *parent) : QObject(parent) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
mConfig = core->getConfig();
|
||||
}
|
||||
|
||||
SettingsModel::~SettingsModel() {
|
||||
|
|
@ -44,19 +50,319 @@ std::string SettingsModel::getEntryFullName(const std::string §ion, const st
|
|||
return isReadOnly(section, name) ? name + "/readonly" : name;
|
||||
}
|
||||
|
||||
std::list<std::string> SettingsModel::getVideoDevices() const {
|
||||
QStringList SettingsModel::getVideoDevices() const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
return core->getVideoDevicesList();
|
||||
}
|
||||
|
||||
std::string SettingsModel::getVideoDevice() {
|
||||
return CoreModel::getInstance()->getCore()->getVideoDevice();
|
||||
}
|
||||
|
||||
void SettingsModel::setVideoDevice(const std::string &id) {
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
if (core->getVideoDevice() != id) {
|
||||
CoreModel::getInstance()->getCore()->setVideoDevice(id);
|
||||
emit videoDeviceChanged(id);
|
||||
QStringList result;
|
||||
for (auto &device : core->getVideoDevicesList()) {
|
||||
result.append(Utils::coreStringToAppString(device));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString SettingsModel::getVideoDevice () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return Utils::coreStringToAppString(
|
||||
CoreModel::getInstance()->getCore()->getVideoDevice()
|
||||
);
|
||||
}
|
||||
|
||||
void SettingsModel::setVideoDevice (const QString &device) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
CoreModel::getInstance()->getCore()->setVideoDevice(
|
||||
Utils::appStringToCoreString(device)
|
||||
);
|
||||
emit videoDeviceChanged(device);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Audio.
|
||||
// =============================================================================
|
||||
|
||||
bool SettingsModel::getIsInCall() const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return CoreModel::getInstance()->getCore()->getCallsNb() != 0;
|
||||
}
|
||||
|
||||
void SettingsModel::resetCaptureGraph() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
deleteCaptureGraph();
|
||||
createCaptureGraph();
|
||||
}
|
||||
void SettingsModel::createCaptureGraph() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
mSimpleCaptureGraph =
|
||||
new MediastreamerUtils::SimpleCaptureGraph(Utils::appStringToCoreString(getCaptureDevice()), Utils::appStringToCoreString(getPlaybackDevice()));
|
||||
mSimpleCaptureGraph->start();
|
||||
emit captureGraphRunningChanged(getCaptureGraphRunning());
|
||||
}
|
||||
void SettingsModel::startCaptureGraph() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
if (!getIsInCall()) {
|
||||
if (!mSimpleCaptureGraph) {
|
||||
qDebug() << "Starting capture graph [" << mCaptureGraphListenerCount << "]";
|
||||
createCaptureGraph();
|
||||
}
|
||||
++mCaptureGraphListenerCount;
|
||||
}
|
||||
}
|
||||
void SettingsModel::stopCaptureGraph() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
if (mCaptureGraphListenerCount > 0) {
|
||||
if (--mCaptureGraphListenerCount == 0) {
|
||||
qDebug() << "Stopping capture graph [" << mCaptureGraphListenerCount << "]";
|
||||
deleteCaptureGraph();
|
||||
}
|
||||
}
|
||||
}
|
||||
void SettingsModel::stopCaptureGraphs() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
if (mCaptureGraphListenerCount > 0) {
|
||||
mCaptureGraphListenerCount = 0;
|
||||
deleteCaptureGraph();
|
||||
}
|
||||
}
|
||||
void SettingsModel::deleteCaptureGraph() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
if (mSimpleCaptureGraph) {
|
||||
if (mSimpleCaptureGraph->isRunning()) {
|
||||
mSimpleCaptureGraph->stop();
|
||||
}
|
||||
delete mSimpleCaptureGraph;
|
||||
mSimpleCaptureGraph = nullptr;
|
||||
}
|
||||
}
|
||||
//Force a call on the 'detect' method of all audio filters, updating new or removed devices
|
||||
void SettingsModel::accessCallSettings() {
|
||||
// Audio
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
CoreModel::getInstance()->getCore()->reloadSoundDevices();
|
||||
emit captureDevicesChanged(getCaptureDevices());
|
||||
emit playbackDevicesChanged(getPlaybackDevices());
|
||||
emit playbackDeviceChanged(getPlaybackDevice());
|
||||
emit captureDeviceChanged(getCaptureDevice());
|
||||
emit ringerDeviceChanged(getRingerDevice());
|
||||
emit playbackGainChanged(getPlaybackGain());
|
||||
emit captureGainChanged(getCaptureGain());
|
||||
|
||||
// Media cards must not be used twice (capture card + call) else we will get latencies issues and bad echo calibrations in call.
|
||||
if (!getIsInCall()) {
|
||||
qDebug() << "Starting capture graph from accessing audio panel";
|
||||
startCaptureGraph();
|
||||
}
|
||||
// Video
|
||||
CoreModel::getInstance()->getCore()->reloadVideoDevices();
|
||||
emit videoDevicesChanged(getVideoDevices());
|
||||
}
|
||||
|
||||
void SettingsModel::closeCallSettings() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
stopCaptureGraph();
|
||||
emit captureGraphRunningChanged(getCaptureGraphRunning());
|
||||
}
|
||||
|
||||
bool SettingsModel::getCaptureGraphRunning() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning() && !getIsInCall();
|
||||
}
|
||||
|
||||
float SettingsModel::getMicVolume() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
float v = 0.0;
|
||||
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
v = mSimpleCaptureGraph->getCaptureVolume();
|
||||
}
|
||||
emit micVolumeChanged(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
float SettingsModel::getPlaybackGain() const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
float dbGain = CoreModel::getInstance()->getCore()->getPlaybackGainDb();
|
||||
return MediastreamerUtils::dbToLinear(dbGain);
|
||||
}
|
||||
|
||||
void SettingsModel::setPlaybackGain(float gain) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
float oldGain = getPlaybackGain();
|
||||
CoreModel::getInstance()->getCore()->setPlaybackGainDb(MediastreamerUtils::linearToDb(gain));
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
mSimpleCaptureGraph->setPlaybackGain(gain);
|
||||
}
|
||||
if((int)(oldGain*1000) != (int)(gain*1000))
|
||||
emit playbackGainChanged(gain);
|
||||
}
|
||||
|
||||
float SettingsModel::getCaptureGain() const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
float dbGain = CoreModel::getInstance()->getCore()->getMicGainDb();
|
||||
return MediastreamerUtils::dbToLinear(dbGain);
|
||||
}
|
||||
|
||||
void SettingsModel::setCaptureGain(float gain) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
float oldGain = getCaptureGain();
|
||||
CoreModel::getInstance()->getCore()->setMicGainDb(MediastreamerUtils::linearToDb(gain));
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
mSimpleCaptureGraph->setCaptureGain(gain);
|
||||
}
|
||||
if((int)(oldGain *1000) != (int)(gain *1000))
|
||||
emit captureGainChanged(gain);
|
||||
}
|
||||
|
||||
QStringList SettingsModel::getCaptureDevices () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
|
||||
QStringList list;
|
||||
|
||||
for (const auto &device : core->getExtendedAudioDevices()) {
|
||||
if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityRecord))
|
||||
list << Utils::coreStringToAppString(device->getId());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
QStringList SettingsModel::getPlaybackDevices () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
|
||||
QStringList list;
|
||||
|
||||
for (const auto &device : core->getExtendedAudioDevices()) {
|
||||
if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityPlay))
|
||||
list << Utils::coreStringToAppString(device->getId());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QString SettingsModel::getCaptureDevice () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
auto audioDevice = CoreModel::getInstance()->getCore()->getInputAudioDevice();
|
||||
return Utils::coreStringToAppString(audioDevice? audioDevice->getId() : CoreModel::getInstance()->getCore()->getCaptureDevice());
|
||||
}
|
||||
|
||||
void SettingsModel::setCaptureDevice (const QString &device) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
std::string devId = Utils::appStringToCoreString(device);
|
||||
auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices();
|
||||
auto audioDevice = find_if(list.cbegin(), list.cend(), [&] ( const std::shared_ptr<linphone::AudioDevice> & audioItem) {
|
||||
return audioItem->getId() == devId;
|
||||
});
|
||||
if(audioDevice != list.cend()){
|
||||
CoreModel::getInstance()->getCore()->setCaptureDevice(devId);
|
||||
CoreModel::getInstance()->getCore()->setInputAudioDevice(*audioDevice);
|
||||
emit captureDeviceChanged(device);
|
||||
resetCaptureGraph();
|
||||
}else
|
||||
qWarning() << "Cannot set Capture device. The ID cannot be matched with an existant device : " << device;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QString SettingsModel::getPlaybackDevice () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
auto audioDevice = CoreModel::getInstance()->getCore()->getOutputAudioDevice();
|
||||
return Utils::coreStringToAppString(audioDevice? audioDevice->getId() : CoreModel::getInstance()->getCore()->getPlaybackDevice());
|
||||
}
|
||||
|
||||
void SettingsModel::setPlaybackDevice (const QString &device) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
std::string devId = Utils::appStringToCoreString(device);
|
||||
|
||||
auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices();
|
||||
auto audioDevice = find_if(list.cbegin(), list.cend(), [&] ( const std::shared_ptr<linphone::AudioDevice> & audioItem) {
|
||||
return audioItem->getId() == devId;
|
||||
});
|
||||
if(audioDevice != list.cend()){
|
||||
|
||||
CoreModel::getInstance()->getCore()->setPlaybackDevice(devId);
|
||||
CoreModel::getInstance()->getCore()->setOutputAudioDevice(*audioDevice);
|
||||
emit playbackDeviceChanged(device);
|
||||
resetCaptureGraph();
|
||||
}else
|
||||
qWarning() << "Cannot set Playback device. The ID cannot be matched with an existant device : " << device;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QString SettingsModel::getRingerDevice () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return Utils::coreStringToAppString(
|
||||
CoreModel::getInstance()->getCore()->getRingerDevice()
|
||||
);
|
||||
}
|
||||
|
||||
void SettingsModel::setRingerDevice (const QString &device) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
CoreModel::getInstance()->getCore()->setRingerDevice(
|
||||
Utils::appStringToCoreString(device)
|
||||
);
|
||||
emit ringerDeviceChanged(device);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool SettingsModel::getVideoEnabled() const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return CoreModel::getInstance()->getCore()->videoEnabled();
|
||||
}
|
||||
|
||||
void SettingsModel::setVideoEnabled(const bool enabled) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
core->enableVideoCapture(enabled);
|
||||
core->enableVideoDisplay(enabled);
|
||||
emit videoEnabledChanged(enabled);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool SettingsModel::getEchoCancellationEnabled () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return CoreModel::getInstance()->getCore()->echoCancellationEnabled();
|
||||
}
|
||||
|
||||
void SettingsModel::setEchoCancellationEnabled (bool status) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
CoreModel::getInstance()->getCore()->enableEchoCancellation(status);
|
||||
emit echoCancellationEnabledChanged(status);
|
||||
}
|
||||
|
||||
void SettingsModel::startEchoCancellerCalibration(){
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
CoreModel::getInstance()->getCore()->startEchoCancellerCalibration();
|
||||
}
|
||||
|
||||
int SettingsModel::getEchoCancellationCalibration()const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return CoreModel::getInstance()->getCore()->getEchoCancellationCalibration();
|
||||
}
|
||||
|
||||
bool SettingsModel::getAutomaticallyRecordCallsEnabled () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return !!mConfig->getInt(UiSection, "automatically_record_calls", 0);
|
||||
}
|
||||
|
||||
void SettingsModel::setAutomaticallyRecordCallsEnabled (bool enabled) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
mConfig->setInt(UiSection, "automatically_record_calls", enabled);
|
||||
emit automaticallyRecordCallsEnabledChanged(enabled);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// VFS.
|
||||
// =============================================================================
|
||||
|
||||
bool SettingsModel::getVfsEnabled () const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
return !!mConfig->getInt(UiSection, "vfs_enabled", 0);
|
||||
}
|
||||
|
||||
void SettingsModel::setVfsEnabled (bool enabled) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
mConfig->setInt(UiSection, "vfs_enabled", enabled);
|
||||
emit vfsEnabledChanged(enabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <QObject>
|
||||
#include <QVariantMap>
|
||||
#include <linphone++/linphone.hh>
|
||||
#include "MediastreamerUtils.hpp"
|
||||
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
|
|
@ -40,18 +41,101 @@ public:
|
|||
getEntryFullName(const std::string §ion,
|
||||
const std::string &name) const; // Return the full name of the entry : 'name/readonly' or 'name'
|
||||
|
||||
std::list<std::string> getVideoDevices() const;
|
||||
void setVideoDevice(const std::string &id);
|
||||
std::string getVideoDevice();
|
||||
|
||||
|
||||
static const std::string UiSection;
|
||||
|
||||
std::shared_ptr<linphone::Config> mConfig;
|
||||
|
||||
bool getVfsEnabled() const;
|
||||
void setVfsEnabled(const bool enabled);
|
||||
|
||||
bool getVideoEnabled() const;
|
||||
void setVideoEnabled(const bool enabled);
|
||||
|
||||
bool getAutomaticallyRecordCallsEnabled () const;
|
||||
void setAutomaticallyRecordCallsEnabled (bool enabled);
|
||||
|
||||
bool getEchoCancellationEnabled () const;
|
||||
void setEchoCancellationEnabled (bool enabled);
|
||||
|
||||
// Audio. --------------------------------------------------------------------
|
||||
|
||||
bool getIsInCall() const;
|
||||
void accessCallSettings();
|
||||
void closeCallSettings();
|
||||
|
||||
void startCaptureGraph();
|
||||
void stopCaptureGraph();;
|
||||
void stopCaptureGraphs();
|
||||
void resetCaptureGraph();
|
||||
void createCaptureGraph();
|
||||
void deleteCaptureGraph();
|
||||
bool getCaptureGraphRunning();
|
||||
|
||||
float getMicVolume();
|
||||
|
||||
float getPlaybackGain() const;
|
||||
void setPlaybackGain(float gain);
|
||||
|
||||
float getCaptureGain() const;
|
||||
void setCaptureGain(float gain);
|
||||
|
||||
QStringList getCaptureDevices () const;
|
||||
QStringList getPlaybackDevices () const;
|
||||
|
||||
QString getCaptureDevice () const;
|
||||
void setCaptureDevice (const QString &device);
|
||||
|
||||
QString getPlaybackDevice () const;
|
||||
void setPlaybackDevice (const QString &device);
|
||||
|
||||
QString getRingerDevice () const;
|
||||
void setRingerDevice (const QString &device);
|
||||
|
||||
QString getRingPath () const;
|
||||
void setRingPath (const QString &path);
|
||||
|
||||
void startEchoCancellerCalibration();
|
||||
int getEchoCancellationCalibration() const;
|
||||
|
||||
QStringList getVideoDevices () const;
|
||||
|
||||
QString getVideoDevice () const;
|
||||
void setVideoDevice (const QString &device);
|
||||
|
||||
signals:
|
||||
void videoDeviceChanged(const std::string &id);
|
||||
|
||||
// VFS. --------------------------------------------------------------------
|
||||
void vfsEnabledChanged(bool enabled);
|
||||
void videoEnabledChanged(bool enabled);
|
||||
|
||||
// Call. --------------------------------------------------------------------
|
||||
void echoCancellationEnabledChanged(bool enabled);
|
||||
void automaticallyRecordCallsEnabledChanged(bool enabled);
|
||||
|
||||
void captureGraphRunningChanged(bool running);
|
||||
|
||||
void playbackGainChanged(float gain);
|
||||
void captureGainChanged(float gain);
|
||||
|
||||
void captureDevicesChanged (const QStringList &devices);
|
||||
void playbackDevicesChanged (const QStringList &devices);
|
||||
|
||||
void captureDeviceChanged (const QString &device);
|
||||
void playbackDeviceChanged (const QString &device);
|
||||
void ringerDeviceChanged (const QString &device);
|
||||
|
||||
void ringPathChanged (const QString &path);
|
||||
|
||||
void showAudioCodecsChanged (bool status);
|
||||
|
||||
void videoDevicesChanged (const QStringList &devices);
|
||||
void videoDeviceChanged (const QString &device);
|
||||
|
||||
void micVolumeChanged(float volume);
|
||||
|
||||
private:
|
||||
MediastreamerUtils::SimpleCaptureGraph *mSimpleCaptureGraph = nullptr;
|
||||
int mCaptureGraphListenerCount = 0;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
#endif // SETTINGS_MODEL_H_
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import UtilsCpp
|
|||
Item {
|
||||
id: mainItem
|
||||
property var callObj
|
||||
property bool settingsHidden: true
|
||||
|
||||
signal addAccountRequest()
|
||||
|
||||
|
|
@ -134,7 +135,11 @@ Item {
|
|||
{icon: AppIcons.videoconference, selectedIcon: AppIcons.videoconferenceSelected, label: qsTr("Réunions")}
|
||||
]
|
||||
onCurrentIndexChanged: {
|
||||
if (currentIndex === 0) accountProxy.defaultAccount.core.lResetMissedCalls()
|
||||
if (currentIndex === 0) accountProxy.defaultAccount.core.lResetMissedCalls()
|
||||
if (!mainItem.settingsHidden) {
|
||||
mainStackView.pop()
|
||||
mainItem.settingsHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
|
|
@ -337,6 +342,15 @@ Item {
|
|||
iconSize: 32 * DefaultStyle.dp
|
||||
text: qsTr("Paramètres")
|
||||
iconSource: AppIcons.settings
|
||||
onClicked: {
|
||||
if (mainItem.settingsHidden) {
|
||||
mainStackView.push(settingsPageComponent)
|
||||
settingsButton.popup.close()
|
||||
mainItem.settingsHidden = false
|
||||
} else {
|
||||
settingsButton.popup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
IconLabelButton {
|
||||
Layout.preferredHeight: 32 * DefaultStyle.dp
|
||||
|
|
@ -366,22 +380,47 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
StackLayout {
|
||||
id: mainStackLayout
|
||||
currentIndex: tabbar.currentIndex
|
||||
Layout.topMargin: 24 * DefaultStyle.dp
|
||||
CallPage {
|
||||
id: callPage
|
||||
onCreateContactRequested: (name, address) => {
|
||||
mainItem.createContact(name, address)
|
||||
Component {
|
||||
id: mainStackLayoutComponent
|
||||
StackLayout {
|
||||
id: mainStackLayout
|
||||
currentIndex: tabbar.currentIndex
|
||||
CallPage {
|
||||
id: callPage
|
||||
onCreateContactRequested: (name, address) => {
|
||||
mainItem.createContact(name, address)
|
||||
}
|
||||
}
|
||||
ContactPage{
|
||||
id: contactPage
|
||||
}
|
||||
Item{}
|
||||
//ConversationPage{}
|
||||
MeetingPage{}
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: settingsPageComponent
|
||||
SettingsPage {
|
||||
onGoBack: {
|
||||
mainStackView.pop()
|
||||
mainItem.settingsHidden = true
|
||||
}
|
||||
}
|
||||
ContactPage{
|
||||
id: contactPage
|
||||
}
|
||||
Control.StackView {
|
||||
id: mainStackView
|
||||
property Transition noTransition: Transition {
|
||||
PropertyAnimation { property: "opacity"; from: 1; to: 1; duration: 0 }
|
||||
}
|
||||
Item{}
|
||||
//ConversationPage{}
|
||||
MeetingPage{}
|
||||
pushEnter: noTransition
|
||||
pushExit: noTransition
|
||||
popEnter: noTransition
|
||||
popExit: noTransition
|
||||
Layout.topMargin: 24 * DefaultStyle.dp
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
initialItem: mainStackLayoutComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
197
Linphone/view/App/Layout/Settings/CallSettingsLayout.qml
Normal file
197
Linphone/view/App/Layout/Settings/CallSettingsLayout.qml
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
import SettingsCpp 1.0
|
||||
|
||||
GenericSettingsLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Component {
|
||||
id: settings
|
||||
ColumnLayout {
|
||||
spacing: 40 * DefaultStyle.dp
|
||||
SwitchSetting {
|
||||
titleText: qsTr("Activer la vidéo")
|
||||
propertyName: "videoEnabled"
|
||||
}
|
||||
SwitchSetting {
|
||||
titleText: qsTr("Utiliser l'annulateur d'écho")
|
||||
subTitleText: qsTr("Évite que de l'écho soit entendu par votre correspondant")
|
||||
propertyName: "echoCancellationEnabled"
|
||||
}
|
||||
SwitchSetting {
|
||||
titleText: qsTr("Démarrer l'enregistrement des appels automatiquement")
|
||||
propertyName: "automaticallyRecordCallsEnabled"
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
EffectImage {
|
||||
imageSource: AppIcons.videoCamera
|
||||
colorizationColor: DefaultStyle.main1_500_main
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
imageWidth: 24 * DefaultStyle.dp
|
||||
imageHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Caméra")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
ComboSetting {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
model: SettingsCpp.videoDevices
|
||||
propertyName: "videoDevice"
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
EffectImage {
|
||||
imageSource: AppIcons.speaker
|
||||
colorizationColor: DefaultStyle.main1_500_main
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
imageWidth: 24 * DefaultStyle.dp
|
||||
imageHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Haut-parleurs")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
ComboSetting {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
model: SettingsCpp.playbackDevices
|
||||
propertyName: "playbackDevice"
|
||||
}
|
||||
Slider {
|
||||
id: speakerVolume
|
||||
Layout.fillWidth: true
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
value: SettingsCpp.playbackGain
|
||||
onMoved: {
|
||||
SettingsCpp.setPlaybackGain(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
EffectImage {
|
||||
imageSource: AppIcons.speaker
|
||||
colorizationColor: DefaultStyle.main1_500_main
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
imageWidth: 24 * DefaultStyle.dp
|
||||
imageHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Sonnerie")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
ComboSetting {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
model: SettingsCpp.playbackDevices
|
||||
propertyName: "ringerDevice"
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
EffectImage {
|
||||
imageSource: AppIcons.microphone
|
||||
colorizationColor: DefaultStyle.main1_500_main
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
imageWidth: 24 * DefaultStyle.dp
|
||||
imageHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Microphone")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
ComboSetting {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
model: SettingsCpp.captureDevices
|
||||
propertyName: "captureDevice"
|
||||
}
|
||||
Slider {
|
||||
id: microVolume
|
||||
Layout.fillWidth: true
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
value: SettingsCpp.captureGain
|
||||
onMoved: {
|
||||
SettingsCpp.setCaptureGain(value)
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: audioTestSliderTimer
|
||||
running: false
|
||||
interval: 50
|
||||
repeat: true
|
||||
onTriggered: SettingsCpp.updateMicVolume()
|
||||
}
|
||||
Slider {
|
||||
id: audioTestSlider
|
||||
visible: !SettingsCpp.isInCall
|
||||
Layout.fillWidth: true
|
||||
enabled: false
|
||||
Layout.preferredHeight: 10 * DefaultStyle.dp
|
||||
|
||||
background: Rectangle {
|
||||
x: audioTestSlider.leftPadding
|
||||
y: audioTestSlider.topPadding + audioTestSlider.availableHeight / 2 - height / 2
|
||||
implicitWidth: 200 * DefaultStyle.dp
|
||||
implicitHeight: 10 * DefaultStyle.dp
|
||||
width: audioTestSlider.availableWidth
|
||||
height: implicitHeight
|
||||
radius: 2 * DefaultStyle.dp
|
||||
color: DefaultStyle.grey_850
|
||||
|
||||
Rectangle {
|
||||
width: audioTestSlider.visualPosition * parent.width
|
||||
height: parent.height
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Horizontal
|
||||
GradientStop { position: 0.0; color: DefaultStyle.vue_meter_light_green }
|
||||
GradientStop { position: 1.0; color: DefaultStyle.vue_meter_dark_green }
|
||||
}
|
||||
radius: 2 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
handle: Item {visible: false}
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: SettingsCpp
|
||||
onMicVolumeChanged: {
|
||||
audioTestSlider.value = volume
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
SettingsCpp.accessCallSettings()
|
||||
audioTestSliderTimer.running = true
|
||||
}
|
||||
Component.onDestruction: {
|
||||
audioTestSliderTimer.running = false
|
||||
SettingsCpp.closeCallSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
component: settings
|
||||
}
|
||||
55
Linphone/view/App/Layout/Settings/GenericSettingsLayout.qml
Normal file
55
Linphone/view/App/Layout/Settings/GenericSettingsLayout.qml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
|
||||
import Linphone
|
||||
|
||||
Rectangle {
|
||||
id: mainItem
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: DefaultStyle.grey_0
|
||||
|
||||
property string titleText
|
||||
property var component
|
||||
property int horizontalMargin: 17 * DefaultStyle.dp
|
||||
property int verticalMargin: 21 * DefaultStyle.dp
|
||||
|
||||
Control.ScrollView {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 55 * DefaultStyle.dp
|
||||
anchors.topMargin: 85 * DefaultStyle.dp
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
Text {
|
||||
text: titleText
|
||||
font: Typography.h3m
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 10 * DefaultStyle.dp
|
||||
}
|
||||
Rectangle {
|
||||
Layout.preferredWidth: loader.implicitWidth + 2 * mainItem.horizontalMargin
|
||||
Layout.preferredHeight: loader.implicitHeight + 2 * mainItem.verticalMargin
|
||||
color: DefaultStyle.grey_100
|
||||
radius: 15 * DefaultStyle.dp
|
||||
Loader {
|
||||
id:loader
|
||||
anchors.centerIn:parent
|
||||
anchors.topMargin: mainItem.verticalMargin
|
||||
anchors.bottomMargin: mainItem.verticalMargin
|
||||
anchors.leftMargin: mainItem.horizontalMargin
|
||||
anchors.rightMargin: mainItem.horizontalMargin
|
||||
sourceComponent: mainItem.component
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
24
Linphone/view/App/Layout/Settings/SecuritySettingsLayout.qml
Normal file
24
Linphone/view/App/Layout/Settings/SecuritySettingsLayout.qml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
|
||||
import Linphone
|
||||
|
||||
GenericSettingsLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Component {
|
||||
id: settings
|
||||
ColumnLayout {
|
||||
spacing: 40 * DefaultStyle.dp
|
||||
SwitchSetting {
|
||||
titleText: qsTr("Chiffrer tous les fichiers")
|
||||
subTitleText: qsTr("Attention, vous ne pourrez pas revenir en arrière !")
|
||||
propertyName: "vfsEnabled"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
component: settings
|
||||
}
|
||||
|
|
@ -18,6 +18,10 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Layout/RightPanelLayout.qml
|
||||
view/Layout/Section.qml
|
||||
|
||||
view/App/Layout/Settings/GenericSettingsLayout.qml
|
||||
view/App/Layout/Settings/SecuritySettingsLayout.qml
|
||||
view/App/Layout/Settings/CallSettingsLayout.qml
|
||||
|
||||
view/Item/Account/Accounts.qml
|
||||
|
||||
view/Item/Call/CallContactsLists.qml
|
||||
|
|
@ -52,6 +56,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Item/Carousel.qml
|
||||
view/Item/CheckableButton.qml
|
||||
view/Item/CheckBox.qml
|
||||
view/Item/SwitchButton.qml
|
||||
view/Item/ComboBox.qml
|
||||
view/Item/DesktopPopup.qml
|
||||
view/Item/Dialog.qml
|
||||
|
|
@ -88,6 +93,10 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
|
||||
view/Item/Test/ItemsTest.qml
|
||||
|
||||
view/Item/Settings/SettingsFamily.qml
|
||||
view/Item/Settings/SwitchSetting.qml
|
||||
view/Item/Settings/ComboSetting.qml
|
||||
|
||||
view/Page/Login/LoginPage.qml
|
||||
view/Page/Login/RegisterPage.qml
|
||||
view/Page/Login/RegisterCheckingPage.qml
|
||||
|
|
@ -100,7 +109,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Page/Main/ContactPage.qml
|
||||
view/Page/Main/MeetingPage.qml
|
||||
|
||||
|
||||
view/Page/Main/SettingsPage.qml
|
||||
|
||||
view/Tool/utils.js
|
||||
# Prototypes
|
||||
|
|
@ -115,6 +124,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
list(APPEND _LINPHONEAPP_QML_SINGLETONS
|
||||
view/Style/AppIcons.qml
|
||||
view/Style/DefaultStyle.qml
|
||||
view/Style/Typography.qml
|
||||
)
|
||||
|
||||
set(_LINPHONEAPP_QML_FILES ${_LINPHONEAPP_QML_FILES} PARENT_SCOPE)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 49 * DefaultStyle.dp
|
||||
model: SettingsCpp.outputAudioDevicesList
|
||||
model: SettingsCpp.playbackDevices
|
||||
onCurrentTextChanged: {
|
||||
if (mainItem.call) mainItem.call.core.lSetOutputAudioDevice(currentText)
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 49 * DefaultStyle.dp
|
||||
model: SettingsCpp.inputAudioDevicesList
|
||||
model: SettingsCpp.captureDevices
|
||||
onCurrentTextChanged: {
|
||||
if (mainItem.call) mainItem.call.core.lSetInputAudioDevice(currentText)
|
||||
}
|
||||
|
|
@ -163,10 +163,10 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 49 * DefaultStyle.dp
|
||||
model: SettingsCpp.videoDevicesList
|
||||
model: SettingsCpp.videoDevices
|
||||
currentIndex: SettingsCpp.currentVideoDeviceIndex
|
||||
onCurrentTextChanged: {
|
||||
SettingsCpp.lSetVideoDevice(currentText)
|
||||
SettingsCpp.setVideoDevice(currentText)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -175,4 +175,4 @@ ColumnLayout {
|
|||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ Control.ComboBox {
|
|||
property int pixelSize: 14 * DefaultStyle.dp
|
||||
property int weight: 400 * DefaultStyle.dp
|
||||
property int leftMargin: 10 * DefaultStyle.dp
|
||||
property bool oneLine: false
|
||||
|
||||
onConstantImageSourceChanged: if (constantImageSource) selectedItemImg.source = constantImageSource
|
||||
onCurrentIndexChanged: {
|
||||
|
|
@ -59,7 +60,7 @@ Control.ComboBox {
|
|||
id: selectedItemText
|
||||
color: mainItem.enabled ? DefaultStyle.main2_600 : DefaultStyle.grey_400
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 2
|
||||
maximumLineCount: oneLine ? 1 : 2
|
||||
wrapMode: Text.WrapAnywhere
|
||||
font {
|
||||
pixelSize: mainItem.pixelSize
|
||||
|
|
|
|||
28
Linphone/view/Item/Settings/ComboSetting.qml
Normal file
28
Linphone/view/Item/Settings/ComboSetting.qml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
import Linphone
|
||||
import SettingsCpp 1.0
|
||||
import 'qrc:/Linphone/view/Tool/utils.js' as Utils
|
||||
|
||||
ComboBox {
|
||||
id: comboBox
|
||||
Layout.preferredHeight: 49 * DefaultStyle.dp
|
||||
property string propertyName
|
||||
oneLine: true
|
||||
currentIndex: Utils.findIndex(model, function (entry) {
|
||||
return entry === SettingsCpp[propertyName]
|
||||
})
|
||||
onCurrentTextChanged: {
|
||||
binding.when = currentText != SettingsCpp[propertyName]
|
||||
}
|
||||
Binding {
|
||||
id: binding
|
||||
target: SettingsCpp
|
||||
property: propertyName
|
||||
value: comboBox.currentText
|
||||
when: false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
50
Linphone/view/Item/Settings/SettingsFamily.qml
Normal file
50
Linphone/view/Item/Settings/SettingsFamily.qml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls as Control
|
||||
import QtQuick.Layouts 1.0
|
||||
import Linphone
|
||||
|
||||
Rectangle {
|
||||
|
||||
id: mainItem
|
||||
|
||||
height: 50 * DefaultStyle.dp
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
property string titleText
|
||||
property bool isSelected: false
|
||||
|
||||
signal selected()
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.main2_200
|
||||
radius: 35 * DefaultStyle.dp
|
||||
visible: parent.containsMouse || isSelected
|
||||
}
|
||||
Rectangle {
|
||||
id: backgroundRightFiller
|
||||
anchors.right: parent.right
|
||||
color: DefaultStyle.main2_200
|
||||
width: 35 * DefaultStyle.dp
|
||||
height: 50 * DefaultStyle.dp
|
||||
visible: parent.containsMouse || isSelected
|
||||
}
|
||||
onClicked: {
|
||||
mainItem.selected()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
anchors.margins: 25
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: titleText
|
||||
font: Typography.h4
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
47
Linphone/view/Item/Settings/SwitchSetting.qml
Normal file
47
Linphone/view/Item/Settings/SwitchSetting.qml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
import Linphone
|
||||
import SettingsCpp 1.0
|
||||
|
||||
RowLayout {
|
||||
id:mainItem
|
||||
property string titleText
|
||||
property string subTitleText
|
||||
property string propertyName
|
||||
property bool enabled: true
|
||||
spacing : 20 * DefaultStyle.dp
|
||||
property int textWidth: 286 * DefaultStyle.dp
|
||||
ColumnLayout {
|
||||
Layout.preferredWidth: textWidth
|
||||
Text {
|
||||
text: titleText
|
||||
font: Typography.p2
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.maximumWidth: textWidth
|
||||
}
|
||||
Text {
|
||||
text: subTitleText
|
||||
font: Typography.p1
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.maximumWidth: textWidth
|
||||
visible: subTitleText.length > 0
|
||||
}
|
||||
}
|
||||
SwitchButton {
|
||||
id: switchButton
|
||||
Layout.alignment: Qt.AlignRight
|
||||
checked: SettingsCpp[mainItem.propertyName]
|
||||
enabled: mainItem.enabled
|
||||
onToggled: {
|
||||
binding.when = true
|
||||
}
|
||||
}
|
||||
Binding {
|
||||
id: binding
|
||||
target: SettingsCpp
|
||||
property: mainItem.propertyName
|
||||
value: switchButton.checked
|
||||
when: false
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ Control.Slider {
|
|||
height: implicitHeight
|
||||
radius: 30 * DefaultStyle.dp
|
||||
// TODO : change the colors when mockup indicates their names
|
||||
color: "#D9D9D9"
|
||||
color: DefaultStyle.grey_850
|
||||
|
||||
Rectangle {
|
||||
width: mainItem.visualPosition * parent.width
|
||||
|
|
@ -50,4 +50,4 @@ Control.Slider {
|
|||
shadowOpacity: 0.1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
Linphone/view/Item/SwitchButton.qml
Normal file
22
Linphone/view/Item/SwitchButton.qml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2 as Control
|
||||
import Linphone
|
||||
|
||||
Control.AbstractButton {
|
||||
id: mainItem
|
||||
checkable: true
|
||||
width: 32 * DefaultStyle.dp
|
||||
height: 20 * DefaultStyle.dp
|
||||
EffectImage {
|
||||
visible: mainItem.checked
|
||||
imageSource: AppIcons.switchOn
|
||||
//colorizationColor: DefaultStyle.success_500main - not working on this icon.
|
||||
anchors.fill: parent
|
||||
}
|
||||
EffectImage {
|
||||
visible: !mainItem.checked
|
||||
imageSource: AppIcons.switchOff
|
||||
//colorizationColor: DefaultStyle.main2_400 - not working on this icon.
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Qml template used for overview pages : Calls, Contacts, Conversations, Meetings
|
||||
* Qml template used for overview pages : Calls, Contacts, Conversations, Meetings, Settings
|
||||
**/
|
||||
|
||||
import QtQuick 2.15
|
||||
|
|
|
|||
87
Linphone/view/Page/Main/SettingsPage.qml
Normal file
87
Linphone/view/Page/Main/SettingsPage.qml
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
import UtilsCpp 1.0
|
||||
|
||||
AbstractMainPage {
|
||||
|
||||
id: mainItem
|
||||
showDefaultItem: false
|
||||
|
||||
signal goBack()
|
||||
|
||||
function layoutUrl(name) {
|
||||
return "qrc:/Linphone/view/App/Layout/Settings/"+name+".qml"
|
||||
}
|
||||
|
||||
property var settingsFamilies: [
|
||||
{title: "Sécurité", layout: "SecuritySettingsLayout"},
|
||||
{title: "Appels", layout: "CallSettingsLayout"},
|
||||
{title: "Conversations", layout: "ChatSettingsLayout"},
|
||||
{title: "Contacts", layout: "ContactSettingsLayout"},
|
||||
{title: "Réunions", layout: "MeetingsSettingsLayout"},
|
||||
{title: "Réseau", layout: "NetworkSettingsLayout"},
|
||||
{title: "Affichage", layout: "DisplaySettingsLayout"},
|
||||
{title: "Paramètres avancés", layout: "AdvancedSettingsLayout"}
|
||||
]
|
||||
|
||||
leftPanelContent: ColumnLayout {
|
||||
id: leftPanel
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
property int sideMargin: 45 * DefaultStyle.dp
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: leftPanel.sideMargin
|
||||
Layout.rightMargin: leftPanel.sideMargin
|
||||
Button {
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
icon.source: AppIcons.leftArrow
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
}
|
||||
onClicked: {
|
||||
mainItem.goBack()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Paramètres")
|
||||
color: DefaultStyle.main2_700
|
||||
font: Typography.h2
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: settingsFamiliesList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
model: mainItem.settingsFamilies
|
||||
Layout.topMargin: 41 * DefaultStyle.dp
|
||||
Layout.leftMargin: leftPanel.sideMargin
|
||||
property int selectedIndex: 0
|
||||
|
||||
delegate: SettingsFamily {
|
||||
titleText:qsTr(modelData.title)
|
||||
isSelected: settingsFamiliesList.selectedIndex == index
|
||||
onSelected: {
|
||||
settingsFamiliesList.selectedIndex = index
|
||||
rightPanelStackView.clear()
|
||||
rightPanelStackView.push(layoutUrl(modelData.layout), { titleText: modelData.title })
|
||||
}
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
let initialEntry = mainItem.settingsFamilies[settingsFamiliesList.selectedIndex]
|
||||
rightPanelStackView.push(layoutUrl(initialEntry.layout), { titleText: initialEntry.title })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,4 +92,7 @@ QtObject {
|
|||
property string screencast: "image://internal/screencast.svg"
|
||||
property string videoconference: "image://internal/video-conference.svg"
|
||||
property string videoconferenceSelected: "image://internal/video-conference-selected.svg"
|
||||
property string switchOn: "image://internal/switch-on.svg"
|
||||
property string switchOff: "image://internal/switch-off.svg"
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ QtObject {
|
|||
property color grey_400: "#949494"
|
||||
property color grey_500: "#4E4E4E"
|
||||
property color grey_600: "#2E3030"
|
||||
property color grey_850: "#D9D9D9"
|
||||
property color grey_900: "#070707"
|
||||
property color grey_1000: "#000000"
|
||||
|
||||
|
|
@ -30,6 +31,9 @@ QtObject {
|
|||
property color success_500main: "#4FAE80"
|
||||
property color info_500_main: "#4AA8FF"
|
||||
|
||||
property color vue_meter_light_green: "#6FF88D"
|
||||
property color vue_meter_dark_green: "#00D916"
|
||||
|
||||
|
||||
property double dp: 1
|
||||
|
||||
|
|
|
|||
41
Linphone/view/Style/Typography.qml
Normal file
41
Linphone/view/Style/Typography.qml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
|
||||
// Title/H4 - Bloc title
|
||||
property font h4: Qt.font( {
|
||||
family: DefaultStyle.defaultFont,
|
||||
pixelSize: 16 * DefaultStyle.dp,
|
||||
weight: 800 * DefaultStyle.dp
|
||||
})
|
||||
|
||||
// Title/H3M - Bloc title
|
||||
property font h3m: Qt.font( {
|
||||
family: DefaultStyle.defaultFont,
|
||||
pixelSize: 16 * DefaultStyle.dp,
|
||||
weight: 800 * DefaultStyle.dp
|
||||
})
|
||||
|
||||
// Title/H2 - Large bloc title
|
||||
property font h2: Qt.font( {
|
||||
family: DefaultStyle.defaultFont,
|
||||
pixelSize: 29 * DefaultStyle.dp,
|
||||
weight: 800 * DefaultStyle.dp
|
||||
})
|
||||
|
||||
// Text/P2 - Bold, reduced paratraph text
|
||||
property font p2: Qt.font( {
|
||||
family: DefaultStyle.defaultFont,
|
||||
pixelSize: 13 * DefaultStyle.dp,
|
||||
weight: 700 * DefaultStyle.dp
|
||||
})
|
||||
|
||||
// Text/P1 - Paratraph text
|
||||
property font p1: Qt.font( {
|
||||
family: DefaultStyle.defaultFont,
|
||||
pixelSize: 14 * DefaultStyle.dp,
|
||||
weight: 400 * DefaultStyle.dp
|
||||
})
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue