Compare commits
1 Commits
work/tfell
...
work/purpo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a27a1e70f |
@@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
|
|
||||||
project(NeoChat)
|
project(NeoChat)
|
||||||
|
|
||||||
set(KF5_MIN_VERSION "5.87.0")
|
set(KF5_MIN_VERSION "5.86.0")
|
||||||
set(QT_MIN_VERSION "5.15.0")
|
set(QT_MIN_VERSION "5.15.0")
|
||||||
|
|
||||||
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
||||||
@@ -114,13 +114,6 @@ find_package(QCoro REQUIRED)
|
|||||||
|
|
||||||
qcoro_enable_coroutines()
|
qcoro_enable_coroutines()
|
||||||
|
|
||||||
include(FindPkgConfig)
|
|
||||||
pkg_check_modules(GSTREAMER IMPORTED_TARGET gstreamer-sdp-1.0>=1.16 gstreamer-webrtc-1.0>=1.16)
|
|
||||||
|
|
||||||
if(ANDROID)
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/android/version.gradle.in ${CMAKE_BINARY_DIR}/version.gradle)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
install(FILES org.kde.neochat.desktop DESTINATION ${KDE_INSTALL_APPDIR})
|
install(FILES org.kde.neochat.desktop DESTINATION ${KDE_INSTALL_APPDIR})
|
||||||
install(FILES org.kde.neochat.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
|
install(FILES org.kde.neochat.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
|
||||||
install(FILES org.kde.neochat.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps)
|
install(FILES org.kde.neochat.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps)
|
||||||
|
|||||||
0
LICENSES/MIT.txt
Normal file → Executable file
0
LICENSES/MIT.txt
Normal file → Executable file
@@ -6,8 +6,8 @@
|
|||||||
-->
|
-->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.kde.neochat"
|
package="org.kde.neochat"
|
||||||
android:versionName="${versionName}"
|
android:versionName="0.0.1"
|
||||||
android:versionCode="${versionCode}"
|
android:versionCode="1604412458"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="NeoChat" android:icon="@drawable/neochat">
|
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="NeoChat" android:icon="@drawable/neochat">
|
||||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
|
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
SPDX-FileCopyrightText: 2018-2020 Volker Krause <vkrause@kde.org>
|
|
||||||
SPDX-FileCopyrightText: 2019 Nicolas Fella <nicolas.fella@gmx.de>
|
|
||||||
SPDX-FileCopyrightText: 2020 Gabriel Souza Franco <gabrielfrancosouza@gmail.com>
|
|
||||||
SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:3.6.4'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply from: '../version.gradle'
|
|
||||||
def timestamp = (int)(new Date().getTime()/1000)
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
/*******************************************************
|
|
||||||
* The following variables:
|
|
||||||
* - androidBuildToolsVersion,
|
|
||||||
* - androidCompileSdkVersion
|
|
||||||
* - qt5AndroidDir - holds the path to qt android files
|
|
||||||
* needed to build any Qt application
|
|
||||||
* on Android.
|
|
||||||
*
|
|
||||||
* are defined in gradle.properties file. This file is
|
|
||||||
* updated by QtCreator and androiddeployqt tools.
|
|
||||||
* Changing them manually might break the compilation!
|
|
||||||
*******************************************************/
|
|
||||||
|
|
||||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
|
||||||
|
|
||||||
buildToolsVersion androidBuildToolsVersion
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
|
||||||
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
|
|
||||||
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
|
|
||||||
res.srcDirs = [qt5AndroidDir + '/res', 'res']
|
|
||||||
resources.srcDirs = ['src']
|
|
||||||
renderscript.srcDirs = ['src']
|
|
||||||
assets.srcDirs = ['assets']
|
|
||||||
jniLibs.srcDirs = ['libs']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
abortOnError false
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
minSdkVersion qtMinSdkVersion
|
|
||||||
targetSdkVersion qtTargetSdkVersion
|
|
||||||
manifestPlaceholders = [versionName: projectVersionFull, versionCode: timestamp]
|
|
||||||
}
|
|
||||||
|
|
||||||
packagingOptions {
|
|
||||||
exclude 'lib/*/*RemoteObjects*'
|
|
||||||
exclude 'lib/*/*StateMachine*'
|
|
||||||
exclude 'lib/*/*_imageformats_qico_*'
|
|
||||||
exclude 'lib/*/*_imageformats_qicns_*'
|
|
||||||
exclude 'lib/*/*_imageformats_qtga_*'
|
|
||||||
exclude 'lib/*/*_imageformats_qtiff_*'
|
|
||||||
exclude 'lib/*/*_qmltooling_*'
|
|
||||||
}
|
|
||||||
|
|
||||||
aaptOptions {
|
|
||||||
// different syntax than above
|
|
||||||
// see https://android.googlesource.com/platform/frameworks/base/+/refs/heads/pie-release/tools/aapt2/util/Files.h#90
|
|
||||||
ignoreAssetsPattern '!<dir>ECM:!<dir>aclocal:!<dir>doc:!<dir>gtk-doc:!<dir>iso-codes:!<dir>man:!<dir>mime:!<dir>pkgconfig:!<dir>qlogging-categories5:!<file>iso_15924.mo:!<file>iso_3166-2.mo:!<file>iso_3166-3.mo:!<file>iso_4217.mo:!<file>iso_639-2.mo:!<file>iso_639-3.mo:!<file>iso_639-5.mo:!<file>kcodecs5_qt.qm:!<file>kde5_xml_mimetypes.qm'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
|
|
||||||
ext {
|
|
||||||
projectVersionFull = "@NEOCHAT_VERSION@"
|
|
||||||
}
|
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
<p>NeoChat works both on mobile and desktop while providing a consistent user experience.</p>
|
<p>NeoChat works both on mobile and desktop while providing a consistent user experience.</p>
|
||||||
<p xml:lang="az">Vahid istifadəçi interfeysi ilə təmin olunan NeoChat, həm mobil telefonda həm də kompyuterlərdə işləyir.</p>
|
<p xml:lang="az">Vahid istifadəçi interfeysi ilə təmin olunan NeoChat, həm mobil telefonda həm də kompyuterlərdə işləyir.</p>
|
||||||
<p xml:lang="ca">El NeoChat funciona en els mòbils i a l'escriptori, proporcionant una experiència d'usuari coherent.</p>
|
<p xml:lang="ca">El NeoChat funciona en els mòbils i a l'escriptori, proporcionant una experiència d'usuari coherent.</p>
|
||||||
<p xml:lang="ca-valencia">El NeoChat funciona en els mòbils i a l'escriptori, proporcionant una experiència d'usuari coherent.</p>
|
<p xml:lang="ca-valencia">El NeoChat funciona en el mòbils i a l'escriptori, proporcionant un experiència d'usuari coherent.</p>
|
||||||
<p xml:lang="de">NeoChat funktioniert sowohl auf dem Mobiltelefon als auch auf dem Arbeitsfläche und bietet ein einheitliches Benutzererlebnis. </p>
|
<p xml:lang="de">NeoChat funktioniert sowohl auf dem Mobiltelefon als auch auf dem Arbeitsfläche und bietet ein einheitliches Benutzererlebnis. </p>
|
||||||
<p xml:lang="en-GB">NeoChat works both on mobile and desktop while providing a consistent user experience.</p>
|
<p xml:lang="en-GB">NeoChat works both on mobile and desktop while providing a consistent user experience.</p>
|
||||||
<p xml:lang="es">NeoChat funciona en móviles y en el escritorio a la vez que proporciona una experiencia de usuario consistente.</p>
|
<p xml:lang="es">NeoChat funciona en móviles y en el escritorio a la vez que proporciona una experiencia de usuario consistente.</p>
|
||||||
|
|||||||
@@ -37,16 +37,6 @@ add_executable(neochat
|
|||||||
blurhash.cpp
|
blurhash.cpp
|
||||||
blurhashimageprovider.cpp
|
blurhashimageprovider.cpp
|
||||||
joinrulesevent.cpp
|
joinrulesevent.cpp
|
||||||
voip/audiosources.cpp
|
|
||||||
voip/devicemonitor.cpp
|
|
||||||
voip/pipelinemanager.cpp
|
|
||||||
voip/screencast.cpp
|
|
||||||
voip/videosources.cpp
|
|
||||||
voip/waylandscreencast.cpp
|
|
||||||
voip/webrtcfoo.cpp
|
|
||||||
voip/windowmodel.cpp
|
|
||||||
voip/xscreencast.cpp
|
|
||||||
voip/callhandler.cpp
|
|
||||||
../res.qrc
|
../res.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -71,9 +61,21 @@ if(NOT ANDROID)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
|
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
|
||||||
target_link_libraries(neochat PRIVATE Qt::Quick Qt::Qml Qt::Gui Qt::Network Qt::QuickControls2 KF5::I18n KF5::Kirigami2 KF5::Notifications KF5::ConfigCore KF5::ConfigGui KF5::CoreAddons Quotient cmark::cmark ${QTKEYCHAIN_LIBRARIES} QCoro::QCoro PkgConfig::GSTREAMER)
|
target_link_libraries(neochat PRIVATE Qt::Quick Qt::Qml Qt::Gui Qt::Network Qt::QuickControls2 KF5::I18n KF5::Kirigami2 KF5::Notifications KF5::ConfigCore KF5::ConfigGui KF5::CoreAddons Quotient cmark::cmark ${QTKEYCHAIN_LIBRARIES} QCoro::QCoro)
|
||||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
||||||
|
|
||||||
|
if(TARGET KF5::Purpose)
|
||||||
|
function(add_share_plugin name)
|
||||||
|
kcoreaddons_add_plugin(${name} SOURCES ${ARGN} INSTALL_NAMESPACE "kf5/purpose")
|
||||||
|
target_link_libraries(${name} Qt5::Core KF5::Purpose)
|
||||||
|
set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/kf5/purpose")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
add_share_plugin(neochatpurposeplugin neochatpurposeplugin.cpp)
|
||||||
|
target_link_libraries(neochatpurposeplugin KF5::I18n KF5::Service)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if(NEOCHAT_FLATPAK)
|
if(NEOCHAT_FLATPAK)
|
||||||
target_compile_definitions(neochat PRIVATE NEOCHAT_FLATPAK)
|
target_compile_definitions(neochat PRIVATE NEOCHAT_FLATPAK)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -62,26 +62,6 @@ Controller::Controller(QObject *parent)
|
|||||||
Connection::setRoomType<NeoChatRoom>();
|
Connection::setRoomType<NeoChatRoom>();
|
||||||
Connection::setUserType<NeoChatUser>();
|
Connection::setUserType<NeoChatUser>();
|
||||||
|
|
||||||
connect(this, &Controller::connectionAdded, this, [=, this](Connection *connection) {
|
|
||||||
connection->getTurnServers();
|
|
||||||
|
|
||||||
connect(connection, &Connection::turnServersChanged, this, [=, this](const QJsonObject &data) {
|
|
||||||
m_turnServers[connection->userId()].clear();
|
|
||||||
const auto username = QUrl::toPercentEncoding(data["username"].toString());
|
|
||||||
const auto password = QUrl::toPercentEncoding(data["password"].toString());
|
|
||||||
const auto ttl = data["ttl"].toInt();
|
|
||||||
for (const auto &uri : data["uris"].toArray()) {
|
|
||||||
const auto parts = uri.toString().split(":");
|
|
||||||
const auto port = parts[2].split("?")[0];
|
|
||||||
m_turnServers[connection->userId()] +=
|
|
||||||
parts[0] + QStringLiteral("://") + username + QStringLiteral(":") + password + QStringLiteral("@") + parts[1] + QStringLiteral(":") + port;
|
|
||||||
}
|
|
||||||
QTimer::singleShot(1000 * ttl, this, [this, connection]() {
|
|
||||||
connection->getTurnServers();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
#ifndef Q_OS_ANDROID
|
#ifndef Q_OS_ANDROID
|
||||||
TrayIcon *trayIcon = new TrayIcon(this);
|
TrayIcon *trayIcon = new TrayIcon(this);
|
||||||
if (NeoChatConfig::self()->systemTray()) {
|
if (NeoChatConfig::self()->systemTray()) {
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ public Q_SLOTS:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkConfigurationManager *m_mgr;
|
QNetworkConfigurationManager *m_mgr;
|
||||||
QHash<QString, QSet<QString>> m_turnServers; // userId -> List of TURN servers in the format that gstreamer needs
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO libQuotient 0.7: Drop
|
// TODO libQuotient 0.7: Drop
|
||||||
|
|||||||
32
src/main.cpp
32
src/main.cpp
@@ -66,21 +66,8 @@
|
|||||||
#include "colorschemer.h"
|
#include "colorschemer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "voip/audiosources.h"
|
|
||||||
#include "voip/devicemonitor.h"
|
|
||||||
#include "voip/pipelinemanager.h"
|
|
||||||
#include "voip/screencast.h"
|
|
||||||
#include "voip/videosources.h"
|
|
||||||
#include "voip/webrtcfoo.h"
|
|
||||||
#include "voip/windowmodel.h"
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(GstDevice *)
|
|
||||||
Q_DECLARE_METATYPE(GstElement *)
|
|
||||||
|
|
||||||
#ifdef HAVE_KDBUSADDONS
|
#ifdef HAVE_KDBUSADDONS
|
||||||
static void raiseWindow(QWindow *window)
|
static void raiseWindow(QWindow *window)
|
||||||
{
|
{
|
||||||
@@ -184,25 +171,6 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GError *error;
|
|
||||||
if (!gst_init_check(&argc, &argv, &error)) {
|
|
||||||
qWarning() << "Failed to initialize gstreamer";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
WebRTC();
|
|
||||||
|
|
||||||
g_object_unref(gst_element_factory_make("qmlglsink", nullptr));
|
|
||||||
DeviceMonitor::instance();
|
|
||||||
VideoSources::instance();
|
|
||||||
AudioSources::instance();
|
|
||||||
qmlRegisterSingletonInstance("org.kde.voip", 1, 0, "VideoSources", &VideoSources::instance());
|
|
||||||
qmlRegisterSingletonInstance("org.kde.voip", 1, 0, "AudioSources", &AudioSources::instance());
|
|
||||||
qmlRegisterSingletonInstance("org.kde.voip", 1, 0, "ScreenCastManager", &ScreenCastManager::instance());
|
|
||||||
qmlRegisterSingletonInstance("org.kde.voip", 1, 0, "PipelineManager", &PipelineManager::instance());
|
|
||||||
qmlRegisterSingletonInstance("org.kde.voip", 1, 0, "SinkModel", &SinkModel::instance());
|
|
||||||
qmlRegisterSingletonInstance("org.kde.voip", 1, 0, "WindowModel", &WindowModel::instance());
|
|
||||||
qRegisterMetaType<QVector<GstElement *>>();
|
|
||||||
|
|
||||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Controller", &Controller::instance());
|
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Controller", &Controller::instance());
|
||||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Clipboard", &clipboard);
|
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Clipboard", &clipboard);
|
||||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Config", config);
|
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Config", config);
|
||||||
|
|||||||
54
src/neochatpurposeplugin.cpp
Normal file
54
src/neochatpurposeplugin.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu>
|
||||||
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
|
#include <purpose/pluginbase.h>
|
||||||
|
|
||||||
|
#include <KApplicationTrader>
|
||||||
|
#include <KLocalizedString>
|
||||||
|
#include <KPluginFactory>
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QUrlQuery>
|
||||||
|
|
||||||
|
EXPORT_SHARE_VERSION
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class NeoChatShareJob : public Purpose::Job
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit NeoChatShareJob(QObject *parent = nullptr)
|
||||||
|
: Purpose::Job(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class Q_DECL_EXPORT NeoChatPurposePlugin : public Purpose::PluginBase
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
NeoChatPurposePlugin(QObject *parent, const QVariantList &)
|
||||||
|
: Purpose::PluginBase(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Purpose::Job *createJob() const override
|
||||||
|
{
|
||||||
|
return new NeoChatShareJob(nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
K_PLUGIN_CLASS_WITH_JSON(NeoChatPurposePlugin, "neochatpurposeplugin.json")
|
||||||
|
|
||||||
|
#include "neochatpurposeplugin.moc"
|
||||||
|
|
||||||
22
src/neochatpurposeplugin.json
Normal file
22
src/neochatpurposeplugin.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"KPlugin": {
|
||||||
|
"Authors": [
|
||||||
|
{
|
||||||
|
"Name": "Carl Schwan"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Category": "Utilities",
|
||||||
|
|
||||||
|
"Description": "Send vith NeoChat",
|
||||||
|
"Icon": "mail-message",
|
||||||
|
"License": "GPL",
|
||||||
|
"Name": "Send with NeoChat",
|
||||||
|
"X-Purpose-ActionDisplay": "Send with NeoChat..."
|
||||||
|
},
|
||||||
|
"X-Purpose-Configuration": [],
|
||||||
|
"X-Purpose-Constraints": [],
|
||||||
|
"X-Purpose-PluginTypes": [
|
||||||
|
"Export",
|
||||||
|
"ShareUrl"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
// SPDX-FileCopyrightText: 2018-2020 Black Hat <bhat@encom.eu.org>
|
// SPDX-FileCopyrightText: 2018-2020 Black Hat <bhat@encom.eu.org>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
@@ -25,10 +24,6 @@
|
|||||||
#include "csapi/rooms.h"
|
#include "csapi/rooms.h"
|
||||||
#include "csapi/typing.h"
|
#include "csapi/typing.h"
|
||||||
#include "events/accountdataevents.h"
|
#include "events/accountdataevents.h"
|
||||||
#include "events/callanswerevent.h"
|
|
||||||
#include "events/callcandidatesevent.h"
|
|
||||||
#include "events/callhangupevent.h"
|
|
||||||
#include "events/callinviteevent.h"
|
|
||||||
#include "events/reactionevent.h"
|
#include "events/reactionevent.h"
|
||||||
#include "events/roomcanonicalaliasevent.h"
|
#include "events/roomcanonicalaliasevent.h"
|
||||||
#include "events/roommessageevent.h"
|
#include "events/roommessageevent.h"
|
||||||
@@ -41,8 +36,6 @@
|
|||||||
#include "user.h"
|
#include "user.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include "voip/callhandler.h"
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinState)
|
NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinState)
|
||||||
@@ -65,19 +58,6 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(this, &Room::displaynameChanged, this, &NeoChatRoom::displayNameChanged);
|
connect(this, &Room::displaynameChanged, this, &NeoChatRoom::displayNameChanged);
|
||||||
|
|
||||||
connect(this, &Room::callEvent, this, [=](Quotient::Room *, const Quotient::RoomEvent *event) {
|
|
||||||
// TODO throw away older events
|
|
||||||
if (const auto inviteEvent = eventCast<const CallInviteEvent>(event)) {
|
|
||||||
CallHandler::instance().handleInvite(inviteEvent);
|
|
||||||
} else if (const auto answerEvent = eventCast<const CallAnswerEvent>(event)) {
|
|
||||||
CallHandler::instance().handleAnswer(answerEvent);
|
|
||||||
} else if (const auto candidatesEvent = eventCast<const CallCandidatesEvent>(event)) {
|
|
||||||
CallHandler::instance().handleCandidates(candidatesEvent);
|
|
||||||
} else if (const auto hangupEvent = eventCast<const CallHangupEvent>(event)) {
|
|
||||||
CallHandler::instance().handleHangup(hangupEvent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeoChatRoom::uploadFile(const QUrl &url, const QString &body)
|
void NeoChatRoom::uploadFile(const QUrl &url, const QString &body)
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "audiosources.h"
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "devicemonitor.h"
|
|
||||||
|
|
||||||
int AudioSources::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent);
|
|
||||||
return DeviceMonitor::instance().audioSources().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant AudioSources::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (index.row() >= DeviceMonitor::instance().audioSources().size()) {
|
|
||||||
return QVariant(QStringLiteral("DEADBEEF"));
|
|
||||||
}
|
|
||||||
if (role == TitleRole) {
|
|
||||||
return DeviceMonitor::instance().audioSources()[index.row()].title;
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> AudioSources::roleNames() const
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
{TitleRole, "title"},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioSources::AudioSources()
|
|
||||||
: QAbstractListModel()
|
|
||||||
{
|
|
||||||
connect(&DeviceMonitor::instance(), &DeviceMonitor::audioSourceAdded, this, [this]() {
|
|
||||||
beginResetModel();
|
|
||||||
endResetModel();
|
|
||||||
});
|
|
||||||
connect(&DeviceMonitor::instance(), &DeviceMonitor::audioSourceRemoved, this, [this]() {
|
|
||||||
beginResetModel();
|
|
||||||
endResetModel();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCore/QAbstractListModel>
|
|
||||||
|
|
||||||
class AudioSources : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum Roles {
|
|
||||||
TitleRole = Qt::UserRole + 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static AudioSources &instance()
|
|
||||||
{
|
|
||||||
static AudioSources _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
AudioSources();
|
|
||||||
};
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "devicemonitor.h"
|
|
||||||
|
|
||||||
static gboolean deviceCallback(GstBus *bus, GstMessage *message, gpointer user_data)
|
|
||||||
{
|
|
||||||
Q_UNUSED(bus);
|
|
||||||
auto monitor = static_cast<DeviceMonitor *>(user_data);
|
|
||||||
return monitor->callback(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceMonitor::DeviceMonitor()
|
|
||||||
: QObject()
|
|
||||||
, m_monitor(gst_device_monitor_new())
|
|
||||||
{
|
|
||||||
GstBus *bus;
|
|
||||||
GstCaps *caps;
|
|
||||||
|
|
||||||
bus = gst_device_monitor_get_bus(m_monitor);
|
|
||||||
gst_bus_add_watch(bus, deviceCallback, this);
|
|
||||||
gst_object_unref(bus);
|
|
||||||
|
|
||||||
if (!gst_device_monitor_start(m_monitor)) {
|
|
||||||
qWarning() << "Failed to start device monitor";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<AudioSource> DeviceMonitor::audioSources() const
|
|
||||||
{
|
|
||||||
return m_audioSources;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<VideoSource> DeviceMonitor::videoSources() const
|
|
||||||
{
|
|
||||||
return m_videoSources;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceMonitor::handleVideoSource(GstDevice *device)
|
|
||||||
{
|
|
||||||
VideoSource source;
|
|
||||||
source.title = QString(gst_device_get_display_name(device));
|
|
||||||
source.device = device;
|
|
||||||
|
|
||||||
auto caps = gst_device_get_caps(device);
|
|
||||||
auto size = gst_caps_get_size(caps);
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
VideoCap videoCap;
|
|
||||||
GstStructure *cap = gst_caps_get_structure(caps, i);
|
|
||||||
gst_structure_get(cap, "width", G_TYPE_INT, &videoCap.width, "height", G_TYPE_INT, &videoCap.height, nullptr);
|
|
||||||
const auto framerate = gst_structure_get_value(cap, "framerate");
|
|
||||||
if (GST_VALUE_HOLDS_FRACTION(framerate)) {
|
|
||||||
auto numerator = gst_value_get_fraction_numerator(framerate);
|
|
||||||
auto denominator = gst_value_get_fraction_denominator(framerate);
|
|
||||||
videoCap.framerates += (float)numerator / denominator;
|
|
||||||
}
|
|
||||||
// unref cap?
|
|
||||||
source.caps += videoCap;
|
|
||||||
}
|
|
||||||
m_videoSources += source;
|
|
||||||
Q_EMIT videoSourceAdded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceMonitor::handleAudioSource(GstDevice *device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeviceMonitor::callback(GstMessage *message)
|
|
||||||
{
|
|
||||||
GstDevice *device;
|
|
||||||
switch (GST_MESSAGE_TYPE(message)) {
|
|
||||||
case GST_MESSAGE_DEVICE_ADDED: {
|
|
||||||
gst_message_parse_device_added(message, &device);
|
|
||||||
auto name = gst_device_get_display_name(device);
|
|
||||||
auto deviceClass = QString(gst_device_get_device_class(device));
|
|
||||||
if (deviceClass == QStringLiteral("Video/Source")) {
|
|
||||||
handleVideoSource(device);
|
|
||||||
|
|
||||||
} else if (deviceClass == QStringLiteral("Audio/Source")) {
|
|
||||||
AudioSource _device;
|
|
||||||
_device.title = QString(name);
|
|
||||||
m_audioSources += _device;
|
|
||||||
Q_EMIT audioSourceAdded();
|
|
||||||
}
|
|
||||||
g_free(name);
|
|
||||||
gst_object_unref(device);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_MESSAGE_DEVICE_REMOVED: {
|
|
||||||
gst_message_parse_device_removed(message, &device);
|
|
||||||
auto name = gst_device_get_display_name(device);
|
|
||||||
auto deviceClass = QString(gst_device_get_device_class(device));
|
|
||||||
if (deviceClass == QStringLiteral("Video/Source")) {
|
|
||||||
m_videoSources.erase(std::remove_if(m_videoSources.begin(),
|
|
||||||
m_videoSources.end(),
|
|
||||||
[name](VideoSource d) {
|
|
||||||
return d.title == QString(name);
|
|
||||||
}),
|
|
||||||
m_videoSources.end());
|
|
||||||
Q_EMIT videoSourceRemoved();
|
|
||||||
} else if (deviceClass == QStringLiteral("Audio/Source")) {
|
|
||||||
m_audioSources.erase(std::remove_if(m_audioSources.begin(),
|
|
||||||
m_audioSources.end(),
|
|
||||||
[name](AudioSource d) {
|
|
||||||
return d.title == QString(name);
|
|
||||||
}),
|
|
||||||
m_audioSources.end());
|
|
||||||
Q_EMIT audioSourceRemoved();
|
|
||||||
}
|
|
||||||
g_free(name);
|
|
||||||
gst_object_unref(device);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QtCore/QVector>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
struct AudioSource {
|
|
||||||
QString title;
|
|
||||||
};
|
|
||||||
struct VideoCap {
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
QVector<float> framerates;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VideoSource {
|
|
||||||
QString title;
|
|
||||||
GstDevice *device;
|
|
||||||
QVector<VideoCap> caps;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeviceMonitor : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
static DeviceMonitor &instance()
|
|
||||||
{
|
|
||||||
static DeviceMonitor _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<AudioSource> audioSources() const;
|
|
||||||
QVector<VideoSource> videoSources() const;
|
|
||||||
bool callback(GstMessage *message);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void videoSourceAdded();
|
|
||||||
void audioSourceAdded();
|
|
||||||
|
|
||||||
void videoSourceRemoved();
|
|
||||||
void audioSourceRemoved();
|
|
||||||
|
|
||||||
private:
|
|
||||||
DeviceMonitor();
|
|
||||||
GstDeviceMonitor *m_monitor;
|
|
||||||
QVector<AudioSource> m_audioSources;
|
|
||||||
QVector<VideoSource> m_videoSources;
|
|
||||||
void handleVideoSource(GstDevice *device);
|
|
||||||
void handleAudioSource(GstDevice *device);
|
|
||||||
};
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "pipelinemanager.h"
|
|
||||||
#include <QtCore/QDebug>
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(GstElement *);
|
|
||||||
|
|
||||||
PipelineManager::PipelineManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
GstElement *SinkModel::get(int index) const
|
|
||||||
{
|
|
||||||
return m_bins[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void PipelineManager::show(QQuickItem *item, int index)
|
|
||||||
{
|
|
||||||
auto pipeline = gst_pipeline_new(nullptr);
|
|
||||||
|
|
||||||
auto bin = SinkModel::instance().get(index);
|
|
||||||
if (gst_object_get_parent(GST_OBJECT(bin))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GstElement *glUpload = gst_element_factory_make("glupload", nullptr);
|
|
||||||
GstElement *glcolorconvert = gst_element_factory_make("glcolorconvert", nullptr);
|
|
||||||
GstElement *glcolorbalance = gst_element_factory_make("glcolorbalance", nullptr);
|
|
||||||
GstElement *glImageSink = gst_element_factory_make("qmlglsink", nullptr);
|
|
||||||
g_object_set(glImageSink, "widget", item, nullptr);
|
|
||||||
|
|
||||||
gst_bin_add_many(GST_BIN(pipeline), bin, glUpload, glcolorconvert, glcolorbalance, glImageSink, nullptr);
|
|
||||||
gst_element_link_many(bin, glUpload, glcolorconvert, glcolorbalance, glImageSink, nullptr);
|
|
||||||
gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PipelineManager::add(GstElement *bin)
|
|
||||||
{
|
|
||||||
SinkModel::instance().add(bin);
|
|
||||||
}
|
|
||||||
void SinkModel::add(GstElement *bin)
|
|
||||||
{
|
|
||||||
beginInsertRows(QModelIndex(), m_bins.size(), m_bins.size());
|
|
||||||
m_bins += bin;
|
|
||||||
endInsertRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> SinkModel::roleNames() const
|
|
||||||
{
|
|
||||||
return {{Element, "element"}};
|
|
||||||
}
|
|
||||||
|
|
||||||
int SinkModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return m_bins.size();
|
|
||||||
}
|
|
||||||
QVariant SinkModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
return QVariant::fromValue(m_bins[index.row()]);
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCore/QAbstractListModel>
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QtCore/QVector>
|
|
||||||
#include <QtQuick/QQuickItem>
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
class PipelineManager : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
static PipelineManager &instance()
|
|
||||||
{
|
|
||||||
static PipelineManager _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE void show(QQuickItem *item, int index);
|
|
||||||
|
|
||||||
void add(GstElement *bin);
|
|
||||||
|
|
||||||
private:
|
|
||||||
PipelineManager();
|
|
||||||
};
|
|
||||||
|
|
||||||
class SinkModel : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum Roles {
|
|
||||||
Element = Qt::UserRole + 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static SinkModel &instance()
|
|
||||||
{
|
|
||||||
static SinkModel _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
|
||||||
void add(GstElement *bin);
|
|
||||||
GstElement *get(int index) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVector<GstElement *> m_bins;
|
|
||||||
};
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "screencast.h"
|
|
||||||
#include "pipelinemanager.h"
|
|
||||||
#include <QtCore/QByteArray>
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
#include "xscreencast.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ScreenCastManager::ScreenCastManager()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
if (qgetenv("XDG_SESSION_TYPE") == QByteArrayLiteral("wayland")) {
|
|
||||||
qDebug() << "This is wayland";
|
|
||||||
// TODO wayland backend
|
|
||||||
} else if (qgetenv("XDG_SESSION_TYPE") == QByteArrayLiteral("x11")) {
|
|
||||||
qDebug() << "This is x11";
|
|
||||||
m_screencast = new XScreenCast(this);
|
|
||||||
} else {
|
|
||||||
qDebug() << "Unknown linux environment";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractScreenCast::AbstractScreenCast(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenCastManager::requestScreenCast(int index)
|
|
||||||
{
|
|
||||||
if (m_screencast) {
|
|
||||||
PipelineManager::instance().add(m_screencast.value()->request(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QtQuick/QQuickItem>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
/* Abstracts over screen sharing backends
|
|
||||||
* <= 1 will be available
|
|
||||||
* on some platforms (wayland), we can't select the window / screen
|
|
||||||
*/
|
|
||||||
class AbstractScreenCast : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
virtual GstElement *request(int index) = 0;
|
|
||||||
virtual bool canSelectWindow() const = 0;
|
|
||||||
virtual bool canShareScreen() const = 0;
|
|
||||||
AbstractScreenCast(QObject *parent);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ScreenCastManager : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
static ScreenCastManager &instance()
|
|
||||||
{
|
|
||||||
static ScreenCastManager _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE void requestScreenCast(int index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::optional<AbstractScreenCast *> m_screencast;
|
|
||||||
ScreenCastManager();
|
|
||||||
QQuickItem *m_item;
|
|
||||||
};
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "videosources.h"
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
#include "pipelinemanager.h"
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "devicemonitor.h"
|
|
||||||
|
|
||||||
int VideoSources::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent);
|
|
||||||
return DeviceMonitor::instance().videoSources().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant VideoSources::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (index.row() >= DeviceMonitor::instance().videoSources().size()) {
|
|
||||||
return QVariant(QStringLiteral("DEADBEEF"));
|
|
||||||
}
|
|
||||||
if (role == TitleRole) {
|
|
||||||
return DeviceMonitor::instance().videoSources()[index.row()].title;
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> VideoSources::roleNames() const
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
{TitleRole, "title"},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoSources::VideoSources()
|
|
||||||
: QAbstractListModel()
|
|
||||||
{
|
|
||||||
connect(&DeviceMonitor::instance(), &DeviceMonitor::videoSourceAdded, this, [this]() {
|
|
||||||
beginResetModel();
|
|
||||||
endResetModel();
|
|
||||||
});
|
|
||||||
connect(&DeviceMonitor::instance(), &DeviceMonitor::videoSourceRemoved, this, [this]() {
|
|
||||||
beginResetModel();
|
|
||||||
endResetModel();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoSources::foo(int index)
|
|
||||||
{
|
|
||||||
auto device = DeviceMonitor::instance().videoSources()[index].device;
|
|
||||||
|
|
||||||
auto bin = gst_bin_new(nullptr);
|
|
||||||
|
|
||||||
GstElement *videoconvert = gst_element_factory_make("videoconvert", nullptr);
|
|
||||||
// GstElement *videorate = gst_element_factory_make("videorate", nullptr);
|
|
||||||
|
|
||||||
GstElement *filter = gst_element_factory_make("capsfilter", nullptr);
|
|
||||||
GstCaps *caps = gst_caps_new_simple("video/x-raw", "width", G_TYPE_INT, 1920, "height", G_TYPE_INT, 1080, "framerate", GST_TYPE_FRACTION, 5, 1, nullptr);
|
|
||||||
g_object_set(filter, "caps", caps, nullptr);
|
|
||||||
gst_caps_unref(caps);
|
|
||||||
GstElement *deviceElement = gst_device_create_element(device, nullptr);
|
|
||||||
|
|
||||||
gst_bin_add_many(GST_BIN(bin), deviceElement, videoconvert, filter, nullptr);
|
|
||||||
gst_element_link_many(deviceElement, videoconvert, filter, nullptr);
|
|
||||||
|
|
||||||
// GstPad *pad = gst_element_get_static_pad(filter, "src");
|
|
||||||
GstPad *pad = gst_element_get_static_pad(filter, "src");
|
|
||||||
auto ghostpad = gst_ghost_pad_new("src", pad);
|
|
||||||
gst_element_add_pad(bin, ghostpad);
|
|
||||||
gst_object_unref(pad);
|
|
||||||
PipelineManager::instance().add(bin);
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCore/QAbstractListModel>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
class VideoSources : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum Roles {
|
|
||||||
TitleRole = Qt::UserRole + 1,
|
|
||||||
DeviceRole,
|
|
||||||
};
|
|
||||||
|
|
||||||
static VideoSources &instance()
|
|
||||||
{
|
|
||||||
static VideoSources _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
Q_INVOKABLE void foo(int index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
VideoSources();
|
|
||||||
};
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "waylandscreencast.h"
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "windowmodel.h"
|
|
||||||
|
|
||||||
#include <KWindowSystem>
|
|
||||||
|
|
||||||
int WindowModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return KWindowSystem::windows().size();
|
|
||||||
}
|
|
||||||
QVariant WindowModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (role == TitleRole) {
|
|
||||||
return KWindowInfo(KWindowSystem::windows()[index.row()], NET::WMName).name();
|
|
||||||
} else if (role == IdRole) {
|
|
||||||
return KWindowSystem::windows()[index.row()];
|
|
||||||
}
|
|
||||||
return QStringLiteral("FOO");
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> WindowModel::roleNames() const
|
|
||||||
{
|
|
||||||
return {{TitleRole, "title"}, {IdRole, "id"}};
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowModel::WindowModel()
|
|
||||||
{
|
|
||||||
connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, [=]() {
|
|
||||||
beginResetModel();
|
|
||||||
endResetModel();
|
|
||||||
});
|
|
||||||
connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, [=]() {
|
|
||||||
beginResetModel();
|
|
||||||
endResetModel();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCore/QAbstractListModel>
|
|
||||||
|
|
||||||
class WindowModel : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Roles {
|
|
||||||
TitleRole = Qt::UserRole + 1,
|
|
||||||
IdRole,
|
|
||||||
};
|
|
||||||
|
|
||||||
static WindowModel &instance()
|
|
||||||
{
|
|
||||||
static WindowModel _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
WindowModel();
|
|
||||||
};
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "xscreencast.h"
|
|
||||||
|
|
||||||
GstElement *XScreenCast::request(int index)
|
|
||||||
{
|
|
||||||
GstElement *bin = gst_bin_new(nullptr);
|
|
||||||
qDebug() << "index" << index;
|
|
||||||
GstElement *ximagesrc = gst_element_factory_make("ximagesrc", "ximagesrc");
|
|
||||||
g_object_set(ximagesrc, "xid", index, nullptr);
|
|
||||||
g_object_set(ximagesrc, "use-damage", true, nullptr);
|
|
||||||
|
|
||||||
// GstElement *filter = gst_element_factory_make("capsfilter", "capsfilter");
|
|
||||||
// GstCaps *caps = gst_caps_new_simple("video/x-raw", "width", G_TYPE_INT, 1920, "height", G_TYPE_INT, 1080, "framerate", GST_TYPE_FRACTION, 30, 1,
|
|
||||||
// nullptr); g_object_set(filter, "caps", caps, nullptr); gst_caps_unref(caps);
|
|
||||||
|
|
||||||
GstElement *queue = gst_element_factory_make("queue", "queue");
|
|
||||||
gst_bin_add_many(GST_BIN(bin), ximagesrc, queue, /*filter,*/ nullptr);
|
|
||||||
gst_element_link_many(ximagesrc, queue /*, filter*/, nullptr);
|
|
||||||
|
|
||||||
// GstPad *pad = gst_element_get_static_pad(filter, "src");
|
|
||||||
GstPad *pad = gst_element_get_static_pad(queue, "src");
|
|
||||||
auto ghostpad = gst_ghost_pad_new("src", pad);
|
|
||||||
gst_element_add_pad(bin, ghostpad);
|
|
||||||
gst_object_unref(pad);
|
|
||||||
|
|
||||||
return bin;
|
|
||||||
}
|
|
||||||
|
|
||||||
XScreenCast::XScreenCast(QObject *parent)
|
|
||||||
: AbstractScreenCast(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool XScreenCast::canSelectWindow() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool XScreenCast::canShareScreen() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "screencast.h"
|
|
||||||
|
|
||||||
class XScreenCast : public AbstractScreenCast
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GstElement *request(int index) override;
|
|
||||||
XScreenCast(QObject *parent);
|
|
||||||
bool canShareScreen() const override;
|
|
||||||
bool canSelectWindow() const override;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user