mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 03:18:07 +00:00
sound player
This commit is contained in:
parent
6ff3cc0ae7
commit
6aadc2f292
28 changed files with 1085 additions and 133 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -3,4 +3,4 @@ path = external/linphone-sdk
|
|||
url = https://gitlab.linphone.org/BC/public/linphone-sdk.git
|
||||
[submodule "external/qtkeychain"]
|
||||
path = external/qtkeychain
|
||||
url = https://github.com/frankosterfeld/qtkeychain.git
|
||||
url = https://gitlab.linphone.org/BC/public/external/qtkeychain.git
|
||||
|
|
@ -206,7 +206,7 @@ set(ENABLE_CSHARP_WRAPPER OFF CACHE BOOL "Build the CSharp wrapper for Liblinpho
|
|||
set(ENABLE_THEORA OFF)
|
||||
set(ENABLE_QT_GL ${ENABLE_VIDEO})
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Core5Compat)
|
||||
|
||||
if(NOT Qt6_FOUND)
|
||||
message(FATAL_ERROR "Minimum supported Qt6!")
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
#include "core/search/MagicSearchProxy.hpp"
|
||||
#include "core/setting/SettingsCore.hpp"
|
||||
#include "core/singleapplication/singleapplication.h"
|
||||
#include "core/sound-player/SoundPlayerGui.hpp"
|
||||
#include "core/timezone/TimeZoneProxy.hpp"
|
||||
#include "core/translator/DefaultTranslatorCore.hpp"
|
||||
#include "core/variant/VariantList.hpp"
|
||||
|
|
@ -684,6 +685,7 @@ void App::initCppInterfaces() {
|
|||
qmlRegisterType<CameraGui>(Constants::MainQmlUri, 1, 0, "CameraGui");
|
||||
qmlRegisterType<FPSCounter>(Constants::MainQmlUri, 1, 0, "FPSCounter");
|
||||
qmlRegisterType<EmojiModel>(Constants::MainQmlUri, 1, 0, "EmojiModel");
|
||||
qmlRegisterType<SoundPlayerGui>(Constants::MainQmlUri, 1, 0, "SoundPlayerGui");
|
||||
|
||||
qmlRegisterType<TimeZoneProxy>(Constants::MainQmlUri, 1, 0, "TimeZoneProxy");
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,9 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
core/screen/ScreenList.cpp
|
||||
core/screen/ScreenProxy.cpp
|
||||
|
||||
core/sound-player/SoundPlayerCore.cpp
|
||||
core/sound-player/SoundPlayerGui.cpp
|
||||
|
||||
core/videoSource/VideoSourceDescriptorCore.cpp
|
||||
core/videoSource/VideoSourceDescriptorGui.cpp
|
||||
|
||||
|
|
|
|||
218
Linphone/core/sound-player/SoundPlayerCore.cpp
Normal file
218
Linphone/core/sound-player/SoundPlayerCore.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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 <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/App.hpp"
|
||||
#include "core/setting/SettingsCore.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include "SoundPlayerCore.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(SoundPlayerCore)
|
||||
|
||||
// =============================================================================
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
int ForceCloseTimerInterval = 20;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QSharedPointer<SoundPlayerCore> SoundPlayerCore::create() {
|
||||
auto sharedPointer = QSharedPointer<SoundPlayerCore>(new SoundPlayerCore(), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
SoundPlayerCore::SoundPlayerCore(QObject *parent) {
|
||||
// connect(mForceCloseTimer, &QTimer::timeout, this, &SoundPlayerCore::handleEof);
|
||||
}
|
||||
|
||||
SoundPlayerCore::~SoundPlayerCore() {
|
||||
// mForceCloseTimer->stop();
|
||||
}
|
||||
|
||||
void SoundPlayerCore::setSelf(QSharedPointer<SoundPlayerCore> me) {
|
||||
auto settingsModel = SettingsModel::getInstance();
|
||||
auto coreModel = CoreModel::getInstance();
|
||||
|
||||
mCoreModelConnection = SafeConnection<SoundPlayerCore, CoreModel>::create(me, coreModel);
|
||||
mSettingsModelConnection = SafeConnection<SoundPlayerCore, SettingsModel>::create(me, settingsModel);
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::ringerDeviceChanged, [this, me] {
|
||||
if (mSoundPlayerModel) mSoundPlayerModel->stop(true);
|
||||
else mSettingsModelConnection->invokeToCore([this, me] { buildInternalPlayer(me); });
|
||||
});
|
||||
|
||||
mCoreModelConnection->invokeToModel([this, me, settingsModel, coreModel] { buildInternalPlayer(me); });
|
||||
// mCoreModelConnection->makeConnectToCore(&SoundPlayerCore::sourceChanged, [this, me] {
|
||||
// mCoreModelConnection->invokeToModel([this, me] { buildInternalPlayer(me); });
|
||||
// });
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void SoundPlayerCore::buildInternalPlayer(QSharedPointer<SoundPlayerCore> me) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto coreModel = CoreModel::getInstance();
|
||||
auto settingsModel = SettingsModel::getInstance();
|
||||
|
||||
if (mSoundPlayerModelConnection) mSoundPlayerModelConnection->disconnect();
|
||||
|
||||
auto player = coreModel->getCore()->createLocalPlayer(
|
||||
Utils::appStringToCoreString(mIsRinger ? settingsModel->getRingerDevice()["display_name"].toString()
|
||||
: settingsModel->getPlaybackDevice()["display_name"].toString()),
|
||||
"", nullptr);
|
||||
|
||||
mHasVideo = player->getIsVideoAvailable();
|
||||
mDuration = player->getDuration();
|
||||
|
||||
mSoundPlayerModel = Utils::makeQObject_ptr<SoundPlayerModel>(player);
|
||||
mSoundPlayerModel->setSelf(mSoundPlayerModel);
|
||||
mSoundPlayerModelConnection = SafeConnection<SoundPlayerCore, SoundPlayerModel>::create(me, mSoundPlayerModel);
|
||||
mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lStop, [this](bool force) {
|
||||
mSoundPlayerModelConnection->invokeToModel([this, force] {
|
||||
if (mPlaybackState == LinphoneEnums::PlaybackState::StoppedState && !force) return;
|
||||
mSoundPlayerModel->stop(force);
|
||||
});
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToModel(&SoundPlayerModel::stopped, [this, me](bool force) {
|
||||
if (force) buildInternalPlayer(me);
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lPause, [this]() {
|
||||
mSoundPlayerModelConnection->invokeToModel([this] { mSoundPlayerModel->pause(); });
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToModel(
|
||||
&SoundPlayerModel::playbackStateChanged, [this](LinphoneEnums::PlaybackState state) {
|
||||
mSoundPlayerModelConnection->invokeToCore([this, state] { setPlaybackState(state); });
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lOpen, [this]() {
|
||||
mSoundPlayerModelConnection->invokeToModel([this] { mSoundPlayerModel->open(mSource); });
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lPlay, [this]() {
|
||||
mSoundPlayerModelConnection->invokeToModel([this] { mSoundPlayerModel->play(mSource); });
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lSeek, [this](int offset) {
|
||||
mSoundPlayerModelConnection->invokeToModel([this, offset] { mSoundPlayerModel->seek(offset); });
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToModel(&SoundPlayerModel::positionChanged, [this](int pos) {
|
||||
mSoundPlayerModelConnection->invokeToCore([this, pos] { setPosition(pos); });
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lRefreshPosition, [this]() {
|
||||
mSoundPlayerModelConnection->invokeToModel([this] {
|
||||
auto pos = mSoundPlayerModel->getPosition();
|
||||
mSoundPlayerModelConnection->invokeToModel([this, pos] { setPosition(pos); });
|
||||
});
|
||||
});
|
||||
mSoundPlayerModelConnection->makeConnectToModel(&SoundPlayerModel::eofReached,
|
||||
[this](const shared_ptr<linphone::Player> &player) {
|
||||
mSoundPlayerModelConnection->invokeToCore([this] {
|
||||
mForceClose = true;
|
||||
handleEof();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int SoundPlayerCore::getPosition() const {
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
void SoundPlayerCore::setPosition(int position) {
|
||||
if (mPosition != position) {
|
||||
mPosition = position;
|
||||
emit positionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundPlayerCore::hasVideo() const {
|
||||
return mHasVideo;
|
||||
}
|
||||
|
||||
void SoundPlayerCore::handleEof() {
|
||||
if (mForceClose) {
|
||||
mForceClose = false;
|
||||
lStop();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundPlayerCore::setError(const QString &message) {
|
||||
qWarning() << message;
|
||||
mError = message;
|
||||
emit errorChanged(message);
|
||||
}
|
||||
|
||||
QString SoundPlayerCore::getSource() const {
|
||||
return mSource;
|
||||
}
|
||||
|
||||
void SoundPlayerCore::setSource(const QString &source) {
|
||||
if (source == mSource) return;
|
||||
|
||||
lStop(true);
|
||||
mSource = source;
|
||||
|
||||
emit sourceChanged(source);
|
||||
}
|
||||
|
||||
LinphoneEnums::PlaybackState SoundPlayerCore::getPlaybackState() const {
|
||||
return mPlaybackState;
|
||||
}
|
||||
|
||||
void SoundPlayerCore::setPlaybackState(LinphoneEnums::PlaybackState playbackState) {
|
||||
if (mPlaybackState != playbackState) {
|
||||
mPlaybackState = playbackState;
|
||||
emit playbackStateChanged(playbackState);
|
||||
}
|
||||
// switch (playbackState) {
|
||||
// case PlayingState:
|
||||
// lPlay();
|
||||
// break;
|
||||
// case PausedState:
|
||||
// lPause();
|
||||
// break;
|
||||
// case StoppedState:
|
||||
// lStop();
|
||||
// break;
|
||||
// case ErrorState:
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int SoundPlayerCore::getDuration() const {
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
QDateTime SoundPlayerCore::getCreationDateTime() const {
|
||||
QFileInfo fileInfo(mSource);
|
||||
QDateTime creationDate = fileInfo.birthTime();
|
||||
return creationDate.isValid() ? creationDate : fileInfo.lastModified();
|
||||
}
|
||||
|
||||
QString SoundPlayerCore::getBaseName() const {
|
||||
return QFileInfo(mSource).baseName();
|
||||
}
|
||||
115
Linphone/core/sound-player/SoundPlayerCore.hpp
Normal file
115
Linphone/core/sound-player/SoundPlayerCore.hpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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 SOUND_PLAYER_MODEL_H_
|
||||
#define SOUND_PLAYER_MODEL_H_
|
||||
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/setting/SettingsModel.hpp"
|
||||
#include "model/sound-player/SoundPlayerModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class QTimer;
|
||||
|
||||
class SoundPlayerCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString source READ getSource WRITE setSource NOTIFY sourceChanged)
|
||||
Q_PROPERTY(QString baseName READ getBaseName NOTIFY sourceChanged)
|
||||
Q_PROPERTY(LinphoneEnums::PlaybackState playbackState READ getPlaybackState WRITE setPlaybackState NOTIFY
|
||||
playbackStateChanged)
|
||||
Q_PROPERTY(int duration READ getDuration NOTIFY sourceChanged)
|
||||
Q_PROPERTY(int position READ getPosition WRITE setPosition NOTIFY positionChanged)
|
||||
Q_PROPERTY(bool isRinger MEMBER mIsRinger)
|
||||
Q_PROPERTY(QDateTime creationDateTime READ getCreationDateTime NOTIFY sourceChanged)
|
||||
|
||||
public:
|
||||
static QSharedPointer<SoundPlayerCore> create();
|
||||
SoundPlayerCore(QObject *parent = Q_NULLPTR);
|
||||
~SoundPlayerCore();
|
||||
void setSelf(QSharedPointer<SoundPlayerCore> me);
|
||||
|
||||
int getPosition() const;
|
||||
void setPosition(int position);
|
||||
bool hasVideo() const; // Call it after playing a video because the detection is not outside this scope.
|
||||
|
||||
int getDuration() const;
|
||||
QDateTime getCreationDateTime() const;
|
||||
QString getBaseName() const;
|
||||
|
||||
QString getSource() const;
|
||||
void setSource(const QString &source);
|
||||
|
||||
LinphoneEnums::PlaybackState getPlaybackState() const;
|
||||
void setPlaybackState(LinphoneEnums::PlaybackState playbackState);
|
||||
|
||||
signals:
|
||||
bool lOpen();
|
||||
void lPause();
|
||||
bool lPlay();
|
||||
void lStop(bool force = false);
|
||||
void lSeek(int offset);
|
||||
void lRefreshPosition();
|
||||
|
||||
void paused();
|
||||
void playing();
|
||||
void stopped();
|
||||
void errorChanged(QString error);
|
||||
|
||||
void sourceChanged(const QString &source);
|
||||
void playbackStateChanged(LinphoneEnums::PlaybackState playbackState);
|
||||
void positionChanged();
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
||||
void buildInternalPlayer(QSharedPointer<SoundPlayerCore> me);
|
||||
|
||||
void handleEof();
|
||||
void setError(const QString &message);
|
||||
|
||||
QString mSource;
|
||||
LinphoneEnums::PlaybackState mPlaybackState = LinphoneEnums::PlaybackState::StoppedState;
|
||||
bool mIsRinger = false;
|
||||
|
||||
bool mHasVideo = false;
|
||||
int mPosition = 0;
|
||||
int mDuration = 0;
|
||||
QString mError;
|
||||
|
||||
bool mForceClose = false;
|
||||
QMutex mForceCloseMutex;
|
||||
|
||||
QTimer *mForceCloseTimer = nullptr;
|
||||
|
||||
std::shared_ptr<SoundPlayerModel> mSoundPlayerModel;
|
||||
QSharedPointer<SafeConnection<SoundPlayerCore, SoundPlayerModel>> mSoundPlayerModelConnection;
|
||||
QSharedPointer<SafeConnection<SoundPlayerCore, CoreModel>> mCoreModelConnection;
|
||||
QSharedPointer<SafeConnection<SoundPlayerCore, SettingsModel>> mSettingsModelConnection;
|
||||
};
|
||||
|
||||
#endif // SOUND_PLAYER_MODEL_H_
|
||||
53
Linphone/core/sound-player/SoundPlayerGui.cpp
Normal file
53
Linphone/core/sound-player/SoundPlayerGui.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "SoundPlayerGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(SoundPlayerGui)
|
||||
|
||||
SoundPlayerGui::SoundPlayerGui(QObject *parent) : QObject(parent) {
|
||||
mustBeInMainThread(getClassName());
|
||||
mCore = SoundPlayerCore::create();
|
||||
if (mCore) connect(mCore.get(), &SoundPlayerCore::sourceChanged, this, &SoundPlayerGui::sourceChanged);
|
||||
if (mCore) connect(mCore.get(), &SoundPlayerCore::stopped, this, &SoundPlayerGui::stopped);
|
||||
if (mCore) connect(mCore.get(), &SoundPlayerCore::positionChanged, this, &SoundPlayerGui::positionChanged);
|
||||
}
|
||||
SoundPlayerGui::SoundPlayerGui(QSharedPointer<SoundPlayerCore> core) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
mCore = core;
|
||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||
}
|
||||
|
||||
SoundPlayerGui::~SoundPlayerGui() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
SoundPlayerCore *SoundPlayerGui::getCore() const {
|
||||
return mCore.get();
|
||||
}
|
||||
|
||||
QString SoundPlayerGui::getSource() const {
|
||||
return mCore ? mCore->getSource() : QString();
|
||||
}
|
||||
|
||||
void SoundPlayerGui::setSource(QString source) {
|
||||
if (mCore) mCore->setSource(source);
|
||||
}
|
||||
52
Linphone/core/sound-player/SoundPlayerGui.hpp
Normal file
52
Linphone/core/sound-player/SoundPlayerGui.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 SOUND_PLAYER_GUI_H_
|
||||
#define SOUND_PLAYER_GUI_H_
|
||||
|
||||
#include "SoundPlayerCore.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class SoundPlayerGui : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(SoundPlayerCore *core READ getCore CONSTANT)
|
||||
Q_PROPERTY(QString source READ getSource WRITE setSource NOTIFY sourceChanged)
|
||||
|
||||
public:
|
||||
SoundPlayerGui(QObject *parent = nullptr);
|
||||
SoundPlayerGui(QSharedPointer<SoundPlayerCore> core);
|
||||
~SoundPlayerGui();
|
||||
SoundPlayerCore *getCore() const;
|
||||
QString getSource() const;
|
||||
void setSource(QString source);
|
||||
QSharedPointer<SoundPlayerCore> mCore;
|
||||
|
||||
signals:
|
||||
void sourceChanged();
|
||||
void stopped();
|
||||
void positionChanged();
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
3
Linphone/data/image/pause-fill.svg
Normal file
3
Linphone/data/image/pause-fill.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.1875 3.375V14.625C15.1875 14.9234 15.069 15.2095 14.858 15.4205C14.647 15.6315 14.3609 15.75 14.0625 15.75H11.25C10.9516 15.75 10.6655 15.6315 10.4545 15.4205C10.2435 15.2095 10.125 14.9234 10.125 14.625V3.375C10.125 3.07663 10.2435 2.79048 10.4545 2.5795C10.6655 2.36853 10.9516 2.25 11.25 2.25H14.0625C14.3609 2.25 14.647 2.36853 14.858 2.5795C15.069 2.79048 15.1875 3.07663 15.1875 3.375ZM6.75 2.25H3.9375C3.63913 2.25 3.35298 2.36853 3.142 2.5795C2.93103 2.79048 2.8125 3.07663 2.8125 3.375V14.625C2.8125 14.9234 2.93103 15.2095 3.142 15.4205C3.35298 15.6315 3.63913 15.75 3.9375 15.75H6.75C7.04837 15.75 7.33452 15.6315 7.5455 15.4205C7.75647 15.2095 7.875 14.9234 7.875 14.625V3.375C7.875 3.07663 7.75647 2.79048 7.5455 2.5795C7.33452 2.36853 7.04837 2.25 6.75 2.25Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 907 B |
3
Linphone/data/image/stop-filled.svg
Normal file
3
Linphone/data/image/stop-filled.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 5.38818V18.6118C19.9995 18.9798 19.8531 19.3327 19.5929 19.5929C19.3327 19.8531 18.9798 19.9995 18.6118 20H5.38818C5.02016 19.9995 4.66735 19.8531 4.40712 19.5929C4.14689 19.3327 4.00048 18.9798 4 18.6118V5.38818C4.00048 5.02016 4.14689 4.66735 4.40712 4.40712C4.66735 4.14689 5.02016 4.00048 5.38818 4H18.6118C18.9798 4.00048 19.3327 4.14689 19.5929 4.40712C19.8531 4.66735 19.9995 5.02016 20 5.38818Z" fill="#343330"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 537 B |
|
|
@ -90,7 +90,7 @@ int main(int argc, char *argv[]) {
|
|||
result = app->exec();
|
||||
} while (result == (int)App::StatusCode::gRestartCode);
|
||||
QString message = "[Main] Exiting app with the code : " + QString::number(result);
|
||||
if (result) qInfo() << message;
|
||||
if (!result) qInfo() << message;
|
||||
else qWarning() << message;
|
||||
app->clean();
|
||||
app = nullptr;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
model/setting/SettingsModel.cpp
|
||||
model/setting/MediastreamerUtils.cpp
|
||||
|
||||
model/sound-player/SoundPlayerModel.cpp
|
||||
|
||||
model/tool/ToolModel.cpp
|
||||
model/tool/VfsUtils.cpp
|
||||
|
|
|
|||
133
Linphone/model/sound-player/SoundPlayerModel.cpp
Normal file
133
Linphone/model/sound-player/SoundPlayerModel.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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 <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include "SoundPlayerModel.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(SoundPlayerModel)
|
||||
|
||||
// =============================================================================
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
int ForceCloseTimerInterval = 20;
|
||||
}
|
||||
|
||||
class SoundPlayerModel::Handlers : public linphone::PlayerListener {
|
||||
public:
|
||||
Handlers(SoundPlayerModel *soundPlayerModel) {
|
||||
mSoundPlayerModel = soundPlayerModel;
|
||||
}
|
||||
|
||||
private:
|
||||
SoundPlayerModel *mSoundPlayerModel;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
SoundPlayerModel::SoundPlayerModel(const std::shared_ptr<linphone::Player> &player, QObject *parent)
|
||||
: ::Listener<linphone::Player, linphone::PlayerListener>(player, parent) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
}
|
||||
|
||||
SoundPlayerModel::~SoundPlayerModel() {
|
||||
if (mMonitor) mMonitor->close();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void SoundPlayerModel::pause() {
|
||||
if (mMonitor->pause()) {
|
||||
//: Unable to pause
|
||||
emit errorChanged("sound_player_pause_error");
|
||||
emit playbackStateChanged(LinphoneEnums::PlaybackState::ErrorState);
|
||||
return;
|
||||
}
|
||||
emit paused();
|
||||
emit playbackStateChanged(LinphoneEnums::PlaybackState::PausedState);
|
||||
}
|
||||
|
||||
bool SoundPlayerModel::open(QString source) {
|
||||
mMonitor->open(Utils::appStringToCoreString(source));
|
||||
emit open();
|
||||
return true;
|
||||
// }
|
||||
// return false;
|
||||
}
|
||||
|
||||
bool SoundPlayerModel::play(QString source) {
|
||||
if (source == "") return false;
|
||||
if (!open(source)) {
|
||||
qWarning() << QStringLiteral("Unable to open: `%1`").arg(source);
|
||||
//: Unable to open: `%1`
|
||||
emit errorChanged(QString("sound_player_open_error").arg(source));
|
||||
return false;
|
||||
}
|
||||
if (mMonitor->start()) {
|
||||
//: Unable to play %1
|
||||
emit errorChanged(QString("sound_player_play_error").arg(source));
|
||||
emit playbackStateChanged(LinphoneEnums::PlaybackState::ErrorState);
|
||||
return false;
|
||||
}
|
||||
emit playing();
|
||||
emit playbackStateChanged(LinphoneEnums::PlaybackState::PlayingState);
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void SoundPlayerModel::seek(int offset) {
|
||||
mMonitor->seek(offset);
|
||||
emit positionChanged(mMonitor->getCurrentPosition());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int SoundPlayerModel::getPosition() const {
|
||||
return mMonitor->getCurrentPosition();
|
||||
}
|
||||
|
||||
bool SoundPlayerModel::hasVideo() const {
|
||||
return mMonitor->getIsVideoAvailable();
|
||||
}
|
||||
|
||||
void SoundPlayerModel::stop(bool force) {
|
||||
if (mMonitor) mMonitor->close();
|
||||
emit stopped(force);
|
||||
emit playbackStateChanged(LinphoneEnums::PlaybackState::StoppedState);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int SoundPlayerModel::getDuration() const {
|
||||
return mMonitor->getDuration();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
void SoundPlayerModel::onEofReached(const shared_ptr<linphone::Player> &player) {
|
||||
if (player == mMonitor) emit eofReached(player);
|
||||
}
|
||||
80
Linphone/model/sound-player/SoundPlayerModel.hpp
Normal file
80
Linphone/model/sound-player/SoundPlayerModel.hpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 SOUND_PLAYER_H_
|
||||
#define SOUND_PLAYER_H_
|
||||
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include <memory>
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class QTimer;
|
||||
|
||||
class SoundPlayerModel : public ::Listener<linphone::Player, linphone::PlayerListener>,
|
||||
public linphone::PlayerListener,
|
||||
public AbstractObject {
|
||||
class Handlers;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SoundPlayerModel(const std::shared_ptr<linphone::Player> &player, QObject *parent = nullptr);
|
||||
~SoundPlayerModel();
|
||||
|
||||
bool open(QString source);
|
||||
void pause();
|
||||
bool play(QString source);
|
||||
void stop(bool force = false);
|
||||
void seek(int offset);
|
||||
|
||||
int getPosition() const;
|
||||
bool hasVideo() const; // Call it after playing a video because the detection is not outside this scope.
|
||||
|
||||
int getDuration() const;
|
||||
|
||||
void handleEof();
|
||||
|
||||
void setError(const QString &message);
|
||||
|
||||
signals:
|
||||
void sourceChanged(const QString &source);
|
||||
|
||||
void paused();
|
||||
void open();
|
||||
void playing();
|
||||
void stopped(bool force);
|
||||
void positionChanged(int position);
|
||||
void errorChanged(QString error);
|
||||
|
||||
void playbackStateChanged(LinphoneEnums::PlaybackState playbackState);
|
||||
|
||||
void eofReached(const std::shared_ptr<linphone::Player> &player);
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
||||
void onEofReached(const std::shared_ptr<linphone::Player> &player);
|
||||
};
|
||||
|
||||
#endif // SOUND_PLAYER_H_
|
||||
|
|
@ -41,7 +41,8 @@ void VideoSourceDescriptorModel::setScreenSharingDisplay(int index) {
|
|||
|
||||
void VideoSourceDescriptorModel::setScreenSharingWindow(void *window) { // Get data from DesktopTools.
|
||||
if (!mDesc) mDesc = linphone::Factory::get()->createVideoSourceDescriptor();
|
||||
else if (getVideoSourceType() == LinphoneEnums::VideoSourceScreenSharingTypeWindow && window == getScreenSharing())
|
||||
else if (getVideoSourceType() == LinphoneEnums::VideoSourceScreenSharingType::VideoSourceScreenSharingTypeWindow &&
|
||||
window == getScreenSharing())
|
||||
return;
|
||||
mDesc->setScreenSharing(linphone::VideoSourceScreenSharingType::Window, window);
|
||||
emit videoDescriptorChanged();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
|
||||
tool/file/FileDownloader.cpp
|
||||
tool/file/FileExtractor.cpp
|
||||
tool/file/TemporaryFile.cpp
|
||||
|
||||
tool/ui/DashRectangle.cpp
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ void LinphoneEnums::registerMetaTypes() {
|
|||
qRegisterMetaType<LinphoneEnums::FriendCapability>();
|
||||
qRegisterMetaType<LinphoneEnums::MediaEncryption>();
|
||||
qRegisterMetaType<LinphoneEnums::ParticipantDeviceState>();
|
||||
qRegisterMetaType<LinphoneEnums::PlaybackState>();
|
||||
qRegisterMetaType<LinphoneEnums::RecorderState>();
|
||||
qRegisterMetaType<LinphoneEnums::RegistrationState>();
|
||||
qRegisterMetaType<LinphoneEnums::TunnelMode>();
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ Q_ENUM_NS(AccountManagerServicesRequestType)
|
|||
// &type); LinphoneEnums::AccountManagerServicesRequestType fromLinphone(const
|
||||
// linphone::AccountManagerServicesRequest::Type &type);
|
||||
|
||||
enum VideoSourceScreenSharingType {
|
||||
enum class VideoSourceScreenSharingType {
|
||||
VideoSourceScreenSharingTypeArea = int(linphone::VideoSourceScreenSharingType::Area),
|
||||
VideoSourceScreenSharingTypeDisplay = int(linphone::VideoSourceScreenSharingType::Display),
|
||||
VideoSourceScreenSharingTypeWindow = int(linphone::VideoSourceScreenSharingType::Window)
|
||||
|
|
@ -393,6 +393,9 @@ Q_ENUM_NS(VideoSourceScreenSharingType)
|
|||
linphone::VideoSourceScreenSharingType toLinphone(const LinphoneEnums::VideoSourceScreenSharingType &type);
|
||||
LinphoneEnums::VideoSourceScreenSharingType fromLinphone(const linphone::VideoSourceScreenSharingType &type);
|
||||
|
||||
enum class PlaybackState { PlayingState = 0, PausedState = 1, StoppedState = 2, ErrorState = 3 };
|
||||
Q_ENUM_NS(PlaybackState);
|
||||
|
||||
} // namespace LinphoneEnums
|
||||
/*
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::CallState)
|
||||
|
|
|
|||
95
Linphone/tool/file/TemporaryFile.cpp
Normal file
95
Linphone/tool/file/TemporaryFile.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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 <QDebug>
|
||||
|
||||
#include "TemporaryFile.hpp"
|
||||
|
||||
#include "core/chat/message/content/ChatMessageContentCore.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/setting/SettingsModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
using namespace std;
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(TemporaryFile)
|
||||
|
||||
TemporaryFile::TemporaryFile(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
TemporaryFile::~TemporaryFile() {
|
||||
deleteFile();
|
||||
}
|
||||
|
||||
void TemporaryFile::createFileFromContent(std::shared_ptr<linphone::Content> content, const bool &exportPlainFile) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
if (content) {
|
||||
QString filePath;
|
||||
if (exportPlainFile || (SettingsModel::getInstance()->getVfsEncrypted() && content->isFileEncrypted()))
|
||||
filePath = Utils::coreStringToAppString(content->exportPlainFile());
|
||||
bool toDelete = true;
|
||||
if (filePath.isEmpty()) {
|
||||
filePath = Utils::coreStringToAppString(content->getFilePath());
|
||||
toDelete = false;
|
||||
if (content->isFileEncrypted()) // filePath was empty while the file is encrypted : it couldn't be decoded.
|
||||
setIsReadable(false);
|
||||
else setIsReadable(true);
|
||||
} else setIsReadable(true);
|
||||
setFilePath(filePath, toDelete);
|
||||
}
|
||||
}
|
||||
|
||||
void TemporaryFile::createFile(const QString &openFilePath, const bool &exportPlainFile) {
|
||||
createFileFromContent(linphone::Factory::get()->createContentFromFile(Utils::appStringToCoreString(openFilePath)),
|
||||
exportPlainFile);
|
||||
}
|
||||
|
||||
QString TemporaryFile::getFilePath() const {
|
||||
return mFilePath;
|
||||
}
|
||||
|
||||
bool TemporaryFile::isReadable() const {
|
||||
return mIsReadable;
|
||||
}
|
||||
|
||||
void TemporaryFile::setFilePath(const QString &path, const bool &toDelete) {
|
||||
if (path != mFilePath) {
|
||||
deleteFile();
|
||||
mFilePath = path;
|
||||
mDeleteFile = toDelete;
|
||||
emit filePathChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TemporaryFile::setIsReadable(const bool &isReadable) {
|
||||
if (isReadable != mIsReadable) {
|
||||
mIsReadable = isReadable;
|
||||
emit isReadableChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TemporaryFile::deleteFile() {
|
||||
if (mDeleteFile && !mFilePath.isEmpty()) QFile::remove(mFilePath);
|
||||
mFilePath = "";
|
||||
}
|
||||
65
Linphone/tool/file/TemporaryFile.hpp
Normal file
65
Linphone/tool/file/TemporaryFile.hpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 TEMPORARY_FILE_H_
|
||||
#define TEMPORARY_FILE_H_
|
||||
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include <QFile>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ContentModel;
|
||||
|
||||
class TemporaryFile : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TemporaryFile(QObject *parent = nullptr);
|
||||
~TemporaryFile();
|
||||
|
||||
Q_PROPERTY(QString filePath READ getFilePath NOTIFY
|
||||
filePathChanged) // not changeable from QML as it comes from a ContentModel
|
||||
Q_PROPERTY(bool isReadable READ isReadable NOTIFY isReadableChanged)
|
||||
|
||||
void createFileFromContent(std::shared_ptr<linphone::Content> content, const bool &exportPlainFile = true);
|
||||
Q_INVOKABLE void createFile(const QString &filePath, const bool &exportPlainFile = true);
|
||||
|
||||
QString getFilePath() const;
|
||||
bool isReadable() const;
|
||||
|
||||
void setFilePath(const QString &path, const bool &toDelete);
|
||||
void setIsReadable(const bool &isReadable);
|
||||
|
||||
void deleteFile();
|
||||
|
||||
signals:
|
||||
void filePathChanged();
|
||||
void isReadableChanged();
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
||||
QString mFilePath;
|
||||
bool mDeleteFile = false;
|
||||
bool mIsReadable = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -46,6 +46,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Control/Display/Flickable.qml
|
||||
view/Control/Display/GradientRectangle.qml
|
||||
view/Control/Display/TemporaryText.qml
|
||||
view/Control/Display/MediaProgressBar.qml
|
||||
view/Control/Display/ProgressBar.qml
|
||||
view/Control/Display/RoundedPane.qml
|
||||
view/Control/Display/RoundProgressBar.qml
|
||||
|
|
|
|||
|
|
@ -11,117 +11,81 @@ Loader{
|
|||
id: mainItem
|
||||
property ChatMessageContentGui chatMessageContentGui
|
||||
property int availableWidth : parent.width
|
||||
property int width: active ? Math.max(availableWidth - ChatAudioMessageStyle.emptySpace, ChatAudioMessageStyle.minWidth) : 0
|
||||
property int fitHeight: active ? 60 : 0
|
||||
|
||||
property font customFont : SettingsModel.textMessageFont
|
||||
property bool isActive: active
|
||||
// property string filePath : tempFile.filePath
|
||||
|
||||
property string filePath : tempFile.filePath
|
||||
active: chatMessageContentGui && chatMessageContentGui.core.isVoiceRecording
|
||||
|
||||
active: chatMessageContentGui && chatMessageContentGui.core.isVoiceRecording()
|
||||
// onChatMessageContentGuiChanged: if(chatMessageContentGui){
|
||||
// tempFile.createFileFromContentModel(chatMessageContentGui, false);
|
||||
// }
|
||||
|
||||
onChatMessageContentGuiChanged: if(chatMessageContentGui){
|
||||
tempFile.createFileFromContentModel(chatMessageContentGui, false);
|
||||
}
|
||||
// TemporaryFile {
|
||||
// id: tempFile
|
||||
// }
|
||||
|
||||
TemporaryFile {
|
||||
id: tempFile
|
||||
}
|
||||
|
||||
sourceComponent: Item{
|
||||
sourceComponent: Item {
|
||||
id: loadedItem
|
||||
property bool isPlaying : vocalPlayer.item && vocalPlayer.item.playbackState === SoundPlayer.PlayingState
|
||||
property bool isPlaying : soundPlayerGui && soundPlayerGui.core.playbackState === LinphoneEnums.PlaybackState.PlayingState
|
||||
onIsPlayingChanged: isPlaying ? mediaProgressBar.resume() : mediaProgressBar.stop()
|
||||
|
||||
width: availableWidth < 0 || availableWidth > mainItem.width ? mainItem.width : availableWidth
|
||||
height: mainItem.fitHeight
|
||||
width: mainItem.width
|
||||
height: mainItem.height
|
||||
|
||||
clip: false
|
||||
Loader {
|
||||
id: vocalPlayer
|
||||
|
||||
active: false
|
||||
|
||||
SoundPlayerGui {
|
||||
id: soundPlayerGui
|
||||
property int duration: mainItem.chatMessageContentGui ? mainItem.chatMessageContentGui.core.fileDuration : core.duration
|
||||
property int position: core.position
|
||||
source: mainItem.chatMessageContentGui && mainItem.chatMessageContentGui.core.filePath
|
||||
|
||||
function play(){
|
||||
if(!vocalPlayer.active)
|
||||
vocalPlayer.active = true
|
||||
else {
|
||||
if(loadedItem.isPlaying){// Pause the play
|
||||
vocalPlayer.item.pause()
|
||||
}else{// Play the audio
|
||||
vocalPlayer.item.play()
|
||||
}
|
||||
if(loadedItem.isPlaying){// Pause the play
|
||||
soundPlayerGui.core.lPause()
|
||||
}else{// Play the audio
|
||||
soundPlayerGui.core.lPlay()
|
||||
}
|
||||
}
|
||||
sourceComponent: SoundPlayer {
|
||||
source: mainItem.chatMessageContentGui && mainItem.filePath
|
||||
onStopped:{
|
||||
mediaProgressBar.value = 101
|
||||
}
|
||||
Component.onCompleted: {
|
||||
play()// This will open the file and allow seeking
|
||||
pause()
|
||||
mediaProgressBar.value = 0
|
||||
mediaProgressBar.refresh()
|
||||
}
|
||||
onStopped: {
|
||||
mediaProgressBar.value = 101
|
||||
}
|
||||
onPositionChanged: {
|
||||
mediaProgressBar.progressPosition = position
|
||||
mediaProgressBar.value = 100 * ( mediaProgressBar.progressPosition / duration)
|
||||
}
|
||||
onSourceChanged: if (source != "") {
|
||||
// core.lPlay()// This will open the file and allow seeking
|
||||
// core.lPause()
|
||||
core.lOpen()
|
||||
mediaProgressBar.value = 0
|
||||
mediaProgressBar.refresh()
|
||||
}
|
||||
onStatusChanged: if (loader.status == Loader.Ready) play()
|
||||
}
|
||||
RowLayout{
|
||||
id: lineLayout
|
||||
|
||||
|
||||
MediaProgressBar{
|
||||
id: mediaProgressBar
|
||||
anchors.fill: parent
|
||||
spacing: 5
|
||||
ActionButton{
|
||||
id: playButton
|
||||
Layout.preferredHeight: iconSize
|
||||
Layout.preferredWidth: iconSize
|
||||
Layout.rightMargin: 5
|
||||
Layout.leftMargin: 15
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
isCustom: true
|
||||
backgroundRadius: width
|
||||
colorSet: (loadedItem.isPlaying ? ChatAudioMessageStyle.pauseAction
|
||||
: ChatAudioMessageStyle.playAction)
|
||||
onClicked:{
|
||||
vocalPlayer.play()
|
||||
progressDuration: soundPlayerGui ? soundPlayerGui.duration : chatMessageContentGui.core.fileDuration
|
||||
progressPosition: 0
|
||||
value: 0
|
||||
function refresh(){
|
||||
if(soundPlayerGui){
|
||||
soundPlayerGui.core.lRefreshPosition()
|
||||
}
|
||||
}
|
||||
Item{
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.rightMargin: 10
|
||||
Layout.topMargin: 10
|
||||
Layout.bottomMargin: 10
|
||||
MediaProgressBar{
|
||||
id: mediaProgressBar
|
||||
anchors.fill: parent
|
||||
progressDuration: vocalPlayer.item ? vocalPlayer.item.duration : chatMessageContentGui.core.getFileDuration()
|
||||
progressPosition: 0
|
||||
value: 0
|
||||
stopAtEnd: true
|
||||
resetAtEnd: false
|
||||
backgroundColor: ChatAudioMessageStyle.backgroundColor.color
|
||||
colorSet: ChatAudioMessageStyle.progressionWave
|
||||
function refresh(){
|
||||
if( vocalPlayer.item){
|
||||
progressPosition = vocalPlayer.item.getPosition()
|
||||
value = 100 * ( progressPosition / vocalPlayer.item.duration)
|
||||
}
|
||||
}
|
||||
onEndReached:{
|
||||
if(vocalPlayer.item)
|
||||
vocalPlayer.item.stop()
|
||||
}
|
||||
onRefreshPositionRequested: refresh()
|
||||
onSeekRequested: if( vocalPlayer.item){
|
||||
vocalPlayer.item.seek(ms)
|
||||
progressPosition = vocalPlayer.item.getPosition()
|
||||
value = 100 * (progressPosition / vocalPlayer.item.duration)
|
||||
}
|
||||
onEndReached:{
|
||||
if(soundPlayerGui)
|
||||
soundPlayerGui.core.lStop()
|
||||
}
|
||||
onPlayStopButtonToggled: soundPlayerGui.play()
|
||||
onRefreshPositionRequested: refresh()
|
||||
onSeekRequested: (ms) => {
|
||||
if(soundPlayerGui) {
|
||||
soundPlayerGui.core.lSeek(ms)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,33 +26,23 @@ ColumnLayout {
|
|||
property int padding: Math.round(10 * DefaultStyle.dp)
|
||||
|
||||
// VOICE MESSAGES
|
||||
// ListView {
|
||||
// id: messagesVoicesList
|
||||
// width: parent.width-2*mainItem.padding
|
||||
// visible: count > 0
|
||||
// spacing: 0
|
||||
// clip: false
|
||||
// model: ChatMessageContentProxy {
|
||||
// filterType: ChatMessageContentProxy.FilterContentType.Voice
|
||||
// chatMessageGui: mainItem.chatMessageGui
|
||||
// }
|
||||
// height: contentHeight
|
||||
// boundsBehavior: Flickable.StopAtBounds
|
||||
// interactive: false
|
||||
// function updateBestWidth(){
|
||||
// var newWidth = mainItem.updateListBestWidth(messagesVoicesList)
|
||||
// mainItem.voicesCount = newWidth[0]
|
||||
// mainItem.voicesBestWidth = newWidth[1]
|
||||
// }
|
||||
// delegate: ChatAudioMessage{
|
||||
// id: audioMessage
|
||||
// contentModel: $modelData
|
||||
// visible: contentModel
|
||||
// z: 1
|
||||
// Component.onCompleted: messagesVoicesList.updateBestWidth()
|
||||
// }
|
||||
// Component.onCompleted: messagesVoicesList.updateBestWidth
|
||||
// }
|
||||
Repeater {
|
||||
id: messagesVoicesList
|
||||
visible: mainItem.chatMessageGui.core.isVoiceRecording && count > 0
|
||||
model: ChatMessageContentProxy{
|
||||
filterType: ChatMessageContentProxy.FilterContentType.Voice
|
||||
chatMessageGui: mainItem.chatMessageGui
|
||||
}
|
||||
delegate: ChatAudioContent {
|
||||
// Layout.fillWidth: true
|
||||
width: Math.round(269 * DefaultStyle.dp)
|
||||
height: Math.round(48 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: height
|
||||
chatMessageContentGui: modelData
|
||||
// width: conferenceList.width
|
||||
// onMouseEvent: (event) => mainItem.mouseEvent(event)
|
||||
}
|
||||
}
|
||||
// CONFERENCE
|
||||
Repeater {
|
||||
id: conferenceList
|
||||
|
|
|
|||
165
Linphone/view/Control/Display/MediaProgressBar.qml
Normal file
165
Linphone/view/Control/Display/MediaProgressBar.qml
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls as Control
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Shapes
|
||||
import QtQuick.Effects
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import Linphone
|
||||
import UtilsCpp
|
||||
|
||||
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
|
||||
|
||||
// =============================================================================
|
||||
|
||||
ProgressBar {
|
||||
id: mainItem
|
||||
|
||||
property bool stopAtEnd: true
|
||||
property bool resetAtEnd: true
|
||||
property int progressDuration // Max duration
|
||||
property int progressPosition // Position of progress bar in [0 ; progressDuration]
|
||||
property bool blockValueAtEnd: true
|
||||
|
||||
property bool recording: false
|
||||
padding: 0
|
||||
clip: true
|
||||
|
||||
function start(){
|
||||
mainItem.value = 0
|
||||
animationTest.start()
|
||||
}
|
||||
function resume(){
|
||||
if(mainItem.value >= 100)
|
||||
mainItem.value = 0
|
||||
animationTest.start()
|
||||
}
|
||||
function stop(){
|
||||
animationTest.stop()
|
||||
}
|
||||
signal playStopButtonToggled()
|
||||
signal endReached()
|
||||
signal refreshPositionRequested()
|
||||
signal seekRequested(int ms)
|
||||
Timer{
|
||||
id: animationTest
|
||||
repeat: true
|
||||
onTriggered: mainItem.refreshPositionRequested()
|
||||
interval: 5
|
||||
}
|
||||
to: 101
|
||||
value: progressPosition * to / progressDuration
|
||||
onValueChanged:{
|
||||
if(value > 100) {
|
||||
if( mainItem.stopAtEnd)
|
||||
stop()
|
||||
if(mainItem.resetAtEnd) {
|
||||
mainItem.value = 0
|
||||
progressPosition = 0
|
||||
} else if(mainItem.blockValueAtEnd){
|
||||
mainItem.value = 100// Stay at 100
|
||||
progressPosition = progressDuration
|
||||
}
|
||||
console.log("end reached")
|
||||
mainItem.endReached()
|
||||
}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
id: backgroundArea
|
||||
anchors.fill: parent
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Horizontal
|
||||
GradientStop { position: 0.0; color: "#FF9E79" }
|
||||
GradientStop { position: 1.0; color: "#FE5E00" }
|
||||
}
|
||||
radius: Math.round(70 * DefaultStyle.dp)
|
||||
}
|
||||
Rectangle {
|
||||
id: mask
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
radius: backgroundArea.radius
|
||||
}
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
id: progressRectangle
|
||||
visible: false
|
||||
Rectangle {
|
||||
color: DefaultStyle.grey_0
|
||||
width: mainItem.barWidth
|
||||
height: backgroundArea.height
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
OpacityMask {
|
||||
anchors.fill: progressRectangle
|
||||
source: progressRectangle
|
||||
maskSource: mask
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: progression
|
||||
anchors.fill: parent
|
||||
onClicked: (mouse) => {
|
||||
mainItem.seekRequested(mouse.x * mainItem.progressDuration/width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contentItem: Item {
|
||||
id: contentRect
|
||||
|
||||
RoundButton {
|
||||
z: parent.z + 1
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Math.round(9 * DefaultStyle.dp)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
icon.width: Math.round(14 * DefaultStyle.dp)
|
||||
icon.height: Math.round(14 * DefaultStyle.dp)
|
||||
icon.source: animationTest.running
|
||||
? mainItem.recording
|
||||
? AppIcons.stopFill
|
||||
: AppIcons.pauseFill
|
||||
: AppIcons.playFill
|
||||
onClicked: {
|
||||
mainItem.playStopButtonToggled()
|
||||
}
|
||||
borderColor: "transparent"
|
||||
style: ButtonStyle.secondary
|
||||
}
|
||||
Control.Control {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Math.round(9 * DefaultStyle.dp)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
leftPadding: Math.round(18 * DefaultStyle.dp)
|
||||
rightPadding: Math.round(18 * DefaultStyle.dp)
|
||||
topPadding: Math.round(5 * DefaultStyle.dp)
|
||||
bottomPadding: Math.round(5 * DefaultStyle.dp)
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.grey_0
|
||||
radius: Math.round(50 * DefaultStyle.dp)
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
spacing: mainItem.recording ? Math.round(5 * DefaultStyle.dp) : 0
|
||||
EffectImage {
|
||||
visible: mainItem.recording
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
imageSource: AppIcons.recordFill
|
||||
}
|
||||
Text {
|
||||
id: durationText
|
||||
text: mainItem.progressPosition > 0 ? UtilsCpp.formatElapsedTime(mainItem.progressPosition / 1000 ) : UtilsCpp.formatElapsedTime(mainItem.progressDuration/1000)
|
||||
font {
|
||||
pixelSize: Typography.p1.pixelSize
|
||||
weight: Typography.p1.weight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Basic
|
||||
import QtQuick.Controls.Basic as Control
|
||||
import Linphone
|
||||
|
||||
ProgressBar {
|
||||
Control.ProgressBar {
|
||||
id: mainItem
|
||||
|
||||
padding: Math.round(3 * DefaultStyle.dp)
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ Control.Control {
|
|||
Flickable {
|
||||
id: sendingAreaFlickable
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width - stackButton.width
|
||||
Layout.preferredHeight: Math.min(Math.round(60 * DefaultStyle.dp), contentHeight)
|
||||
Binding {
|
||||
target: sendingAreaFlickable
|
||||
|
|
@ -159,10 +158,11 @@ Control.Control {
|
|||
}
|
||||
}
|
||||
}
|
||||
StackLayout {
|
||||
RowLayout {
|
||||
id: stackButton
|
||||
currentIndex: sendingTextArea.text.length === 0 ? 0 : 1
|
||||
spacing: 0
|
||||
BigButton {
|
||||
visible: sendingTextArea.text.length === 0
|
||||
style: ButtonStyle.noBackground
|
||||
icon.source: AppIcons.microphone
|
||||
onClicked: {
|
||||
|
|
@ -170,6 +170,7 @@ Control.Control {
|
|||
}
|
||||
}
|
||||
BigButton {
|
||||
visible: sendingTextArea.text.length !== 0
|
||||
style: ButtonStyle.noBackgroundOrange
|
||||
icon.source: AppIcons.paperPlaneRight
|
||||
onClicked: {
|
||||
|
|
|
|||
|
|
@ -863,11 +863,11 @@ FriendGui{
|
|||
ContactEdition {
|
||||
property string objectName: "contactEdition"
|
||||
onCloseEdition: redirectAddress => {
|
||||
goToContactDetails()
|
||||
if (redirectAddress) {
|
||||
initialFriendToDisplay = redirectAddress
|
||||
}
|
||||
}
|
||||
goToContactDetails()
|
||||
if (redirectAddress) {
|
||||
initialFriendToDisplay = redirectAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,8 +74,10 @@ QtObject {
|
|||
property string trustedMask: "image://internal/trusted-mask.svg"
|
||||
property string avatar: "image://internal/randomAvatar.png"
|
||||
property string pause: "image://internal/pause.svg"
|
||||
property string pauseFill: "image://internal/pause-fill.svg"
|
||||
property string play: "image://internal/play.svg"
|
||||
property string playFill: "image://internal/play-fill.svg"
|
||||
property string stopFill: "image://internal/stop-filled.svg"
|
||||
property string filePdf: "image://internal/file-pdf.svg"
|
||||
property string fileText: "image://internal/file-text.svg"
|
||||
property string fileImage: "image://internal/file-image.svg"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue