Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4f6c33f9d | ||
|
|
758ffa8cb5 | ||
|
|
753da8b1d3 | ||
|
|
5f37ab314f | ||
|
|
c7bff3f428 | ||
|
|
34e23f7187 | ||
|
|
c325dd6798 | ||
|
|
b42fde85d1 | ||
|
|
cc379ada85 | ||
|
|
fdb6145bbd | ||
|
|
8bd4d1896a | ||
|
|
1a2d09fe3d | ||
|
|
f01c941c90 | ||
|
|
95d391e869 | ||
|
|
af107168db | ||
|
|
e7e6c5d82b | ||
|
|
ee0c66762d | ||
|
|
c3483a42db | ||
|
|
d68797cebb | ||
|
|
ef221d4574 | ||
|
|
3fa2e3fa3c | ||
|
|
bda1bc0df6 | ||
|
|
cb0f084d42 | ||
|
|
674ac146f2 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
/build
|
/build
|
||||||
|
.vscode
|
||||||
|
|||||||
@@ -18,12 +18,18 @@ find_package(Qt5 CONFIG REQUIRED COMPONENTS
|
|||||||
WebEngineWidgets
|
WebEngineWidgets
|
||||||
)
|
)
|
||||||
|
|
||||||
|
find_package(KF5Notifications)
|
||||||
|
if(KF5Notifications_FOUND)
|
||||||
|
add_definitions( -DKNOTIFICATIONS )
|
||||||
|
endif()
|
||||||
|
|
||||||
set(discord-screenaudio_SRC
|
set(discord-screenaudio_SRC
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/mainwindow.cpp
|
src/mainwindow.cpp
|
||||||
src/virtmic.cpp
|
src/virtmic.cpp
|
||||||
src/discordpage.cpp
|
src/discordpage.cpp
|
||||||
src/streamdialog.cpp
|
src/streamdialog.cpp
|
||||||
|
src/log.cpp
|
||||||
resources.qrc
|
resources.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,6 +58,11 @@ add_executable(discord-screenaudio ${discord-screenaudio_SRC})
|
|||||||
|
|
||||||
target_link_libraries(discord-screenaudio Qt5::Widgets Qt5::WebEngineWidgets rohrkabel)
|
target_link_libraries(discord-screenaudio Qt5::Widgets Qt5::WebEngineWidgets rohrkabel)
|
||||||
|
|
||||||
|
if(KF5Notifications_FOUND)
|
||||||
|
target_link_libraries(discord-screenaudio KF5::Notifications)
|
||||||
|
install(FILES assets/discord-screenaudio.notifyrc DESTINATION ${CMAKE_INSTALL_PREFIX}/share/knotifications5)
|
||||||
|
endif()
|
||||||
|
|
||||||
install(TARGETS discord-screenaudio DESTINATION bin)
|
install(TARGETS discord-screenaudio DESTINATION bin)
|
||||||
install(FILES assets/de.shorsh.discord-screenaudio.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps)
|
install(FILES assets/de.shorsh.discord-screenaudio.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps)
|
||||||
install(PROGRAMS assets/de.shorsh.discord-screenaudio.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
install(PROGRAMS assets/de.shorsh.discord-screenaudio.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -1,12 +1,16 @@
|
|||||||
# discord-screenaudio
|
# discord-screenaudio
|
||||||
|
|
||||||
A very WIP custom discord client that supports streaming with audio on Linux,
|
A custom discord client that supports streaming with audio on Linux, made
|
||||||
made possible by the
|
possible by the
|
||||||
[great work](https://github.com/edisionnano/Screenshare-with-audio-on-Discord-with-Linux)
|
[great work](https://github.com/edisionnano/Screenshare-with-audio-on-Discord-with-Linux)
|
||||||
of [@edisionnano](https://github.com/edisionnano) and the
|
of [@edisionnano](https://github.com/edisionnano) and the
|
||||||
[Rohrkabel library](https://github.com/Soundux/rohrkabel) by
|
[Rohrkabel library](https://github.com/Soundux/rohrkabel) by
|
||||||
[@Curve](https://github.com/Curve).
|
[@Curve](https://github.com/Curve).
|
||||||
|
|
||||||
|
Unlike a lot of other solutions, the audio here is directly fed into the
|
||||||
|
screenshare and not passed to the user microphone
|
||||||
|
([see explanation](#how-it-works)).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The purpose of this project is **not** to provide an alternative to the original
|
The purpose of this project is **not** to provide an alternative to the original
|
||||||
@@ -15,18 +19,31 @@ case you want to stream something, maybe used with a second account. For
|
|||||||
anything else, this client has way too many things that work less well than in
|
anything else, this client has way too many things that work less well than in
|
||||||
the original client.
|
the original client.
|
||||||
|
|
||||||
|
Technically this could be against
|
||||||
|
[Discord's TOS](https://discord.com/terms#software-in-discord%E2%80%99s-services),
|
||||||
|
so be warned. Discord probably won't ban you for using this, but if they do I
|
||||||
|
told you and it's not my fault.
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
- Only works with **PipeWire**
|
- Only works with **PipeWire**
|
||||||
- Only works on **X11**
|
- Can only share primary screen on X11 (no other screens or specific
|
||||||
- Can only share primary screen (no other screens or specific applications) (see
|
applications) (see
|
||||||
[#1](https://github.com/maltejur/discord-screenaudio/issues/1))
|
[#1](https://github.com/maltejur/discord-screenaudio/issues/1))
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
If you are using Arch, you can build and install
|
You have multiple options:
|
||||||
[from the AUR](https://aur.archlinux.org/packages/discord-screenaudio). If you
|
|
||||||
aren't, you will have to [build it yourself](#building-from-source).
|
- Install the Flatpak (recommended):
|
||||||
|
`flatpak install de.shorsh.discord-screenaudio`
|
||||||
|
- If you are on Arch, you can build and install
|
||||||
|
[`discord-screenaudio`](https://aur.archlinux.org/packages/discord-screenaudio)
|
||||||
|
from the AUR
|
||||||
|
- If you are on openSUSE, you can use the
|
||||||
|
[Open Build Service package](https://software.opensuse.org//download.html?project=games%3Atools&package=discord-screenaudio)
|
||||||
|
by [@VortexAcherontic](https://github.com/VortexAcherontic)
|
||||||
|
- You can [build it yourself](#building-from-source)
|
||||||
|
|
||||||
## Building from Source
|
## Building from Source
|
||||||
|
|
||||||
@@ -34,12 +51,12 @@ aren't, you will have to [build it yourself](#building-from-source).
|
|||||||
|
|
||||||
- Basic building tools
|
- Basic building tools
|
||||||
- CMake
|
- CMake
|
||||||
- Qt5 and QtWebEngine
|
- Qt5, QtWebEngine and Kf5Notifications
|
||||||
- **PipeWire** (it currently doesn't work with PulseAudio)
|
- **PipeWire** (it currently doesn't work with PulseAudio)
|
||||||
- Git
|
- Git
|
||||||
|
|
||||||
On Debian:
|
On Debian:
|
||||||
`apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev pkg-config libpipewire-0.3-dev git`
|
`apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev libkf5notifications-dev pkg-config libpipewire-0.3-dev git`
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,22 @@
|
|||||||
<release version="${DISCORD_SCEENAUDIO_VERSION_FULL}" timestamp="${TIMESTAMP}" />
|
<release version="${DISCORD_SCEENAUDIO_VERSION_FULL}" timestamp="${TIMESTAMP}" />
|
||||||
</releases>
|
</releases>
|
||||||
|
|
||||||
<summary>A very WIP custom discord client that supports streaming with audio on Linux</summary>
|
<summary>A custom discord client that supports streaming with audio on Linux</summary>
|
||||||
|
|
||||||
<description>
|
<description>
|
||||||
<p>A very WIP custom discord client that supports streaming with audio on Linux, made possible by the great work of @edisionnano and the Rohrkabel library by @Curve.</p>
|
<p>A custom discord client that supports streaming with audio on Linux, made possible by the great work of @edisionnano and the Rohrkabel library by @Curve.</p>
|
||||||
|
<p>Unlike a lot of other solutions, the audio here is directly fed into the screenshare and not passed to the user microphone.</p>
|
||||||
<p>The purpose of this project is not to provide an alternative to the original Discord client. Rather, it should be used in addition to the original client in case you want to stream something, maybe used with a second account. For anything else, this client has way too many things that work less well than in the original client.</p>
|
<p>The purpose of this project is not to provide an alternative to the original Discord client. Rather, it should be used in addition to the original client in case you want to stream something, maybe used with a second account. For anything else, this client has way too many things that work less well than in the original client.</p>
|
||||||
|
<p>Technically this could be against Discord's TOS, so be warned. Discord probably won't ban you for using this, but if they do I told you and it's not my fault.</p>
|
||||||
|
<p>Known issues:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Only works with PipeWire</li>
|
||||||
|
<li>Can only share primary screen on X11</li>
|
||||||
|
</ul>
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<launchable type="desktop-id">
|
<launchable type="desktop-id">
|
||||||
discord-screenaudio.desktop
|
de.shorsh.discord-screenaudio.desktop
|
||||||
</launchable>
|
</launchable>
|
||||||
|
|
||||||
<screenshots>
|
<screenshots>
|
||||||
@@ -32,4 +39,12 @@
|
|||||||
<provides>
|
<provides>
|
||||||
<binary>discord-screenaudio</binary>
|
<binary>discord-screenaudio</binary>
|
||||||
</provides>
|
</provides>
|
||||||
|
|
||||||
|
<content_rating type="oars-1.0">
|
||||||
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
|
<content_attribute id="social-info">intense</content_attribute>
|
||||||
|
<content_attribute id="social-audio">intense</content_attribute>
|
||||||
|
<content_attribute id="social-contacts">intense</content_attribute>
|
||||||
|
<content_attribute id="money-purchasing">mild</content_attribute>
|
||||||
|
</content_rating>
|
||||||
</component>
|
</component>
|
||||||
8
assets/discord-screenaudio.notifyrc
Normal file
8
assets/discord-screenaudio.notifyrc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[Global]
|
||||||
|
IconName=de.shorsh.discord-screenaudio
|
||||||
|
Name=discord-screenaudio
|
||||||
|
DesktopEntry=de.shorsh.discord-screenaudio.desktop
|
||||||
|
|
||||||
|
[Event/discordNotification]
|
||||||
|
Name=Discord Notification
|
||||||
|
Action=Popup
|
||||||
@@ -3,12 +3,25 @@
|
|||||||
navigator.mediaDevices.chromiumGetDisplayMedia =
|
navigator.mediaDevices.chromiumGetDisplayMedia =
|
||||||
navigator.mediaDevices.getDisplayMedia;
|
navigator.mediaDevices.getDisplayMedia;
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
const getAudioDevice = async (nameOfAudioDevice) => {
|
const getAudioDevice = async (nameOfAudioDevice) => {
|
||||||
await navigator.mediaDevices.getUserMedia({
|
await navigator.mediaDevices.getUserMedia({
|
||||||
audio: true,
|
audio: true,
|
||||||
});
|
});
|
||||||
|
let audioDevice;
|
||||||
|
while (audioDevice === undefined) {
|
||||||
let devices = await navigator.mediaDevices.enumerateDevices();
|
let devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
let audioDevice = devices.find(({ label }) => label === nameOfAudioDevice);
|
audioDevice = devices.find(({ label }) => label === nameOfAudioDevice);
|
||||||
|
if (!audioDevice)
|
||||||
|
console.log(
|
||||||
|
`dsa: Did not find '${nameOfAudioDevice}', trying again in 100ms`
|
||||||
|
);
|
||||||
|
await sleep(100);
|
||||||
|
}
|
||||||
|
console.log(`dsa: Found '${nameOfAudioDevice}'`);
|
||||||
return audioDevice;
|
return audioDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,6 +112,7 @@ setInterval(() => {
|
|||||||
const initialDisplay = el.style.display;
|
const initialDisplay = el.style.display;
|
||||||
|
|
||||||
window.discordScreenaudioStartStream = (width, height, frameRate) => {
|
window.discordScreenaudioStartStream = (width, height, frameRate) => {
|
||||||
|
window.discordScreenaudioResolutionString = `${height}p ${frameRate}FPS`;
|
||||||
setGetDisplayMedia({
|
setGetDisplayMedia({
|
||||||
audio: true,
|
audio: true,
|
||||||
video: { width, height, frameRate },
|
video: { width, height, frameRate },
|
||||||
@@ -134,6 +148,14 @@ setInterval(() => {
|
|||||||
// Remove stream settings if stream is active
|
// Remove stream settings if stream is active
|
||||||
document.getElementById("manage-streams-change-windows")?.remove();
|
document.getElementById("manage-streams-change-windows")?.remove();
|
||||||
document.querySelector(`[aria-label="Stream Settings"]`)?.remove();
|
document.querySelector(`[aria-label="Stream Settings"]`)?.remove();
|
||||||
|
|
||||||
|
if (window.discordScreenaudioResolutionString) {
|
||||||
|
for (const el of document.getElementsByClassName(
|
||||||
|
"qualityIndicator-39wQDy"
|
||||||
|
)) {
|
||||||
|
el.innerHTML = window.discordScreenaudioResolutionString;
|
||||||
|
}
|
||||||
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
// Fix for broken discord notifications after restart
|
// Fix for broken discord notifications after restart
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource>
|
<qresource>
|
||||||
<file>assets/userscript.js</file>
|
<file>assets/userscript.js</file>
|
||||||
|
<file>assets/de.shorsh.discord-screenaudio.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "discordpage.h"
|
#include "discordpage.h"
|
||||||
|
#include "log.h"
|
||||||
#include "virtmic.h"
|
#include "virtmic.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -43,7 +44,7 @@ DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DiscordPage::injectScript(QString source) {
|
void DiscordPage::injectScript(QString source) {
|
||||||
qDebug() << "[main ] Injecting " << source;
|
qDebug(mainLog) << "Injecting " << source;
|
||||||
|
|
||||||
QFile userscript(source);
|
QFile userscript(source);
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ void DiscordPage::featurePermissionRequested(const QUrl &securityOrigin,
|
|||||||
|
|
||||||
if (feature == QWebEnginePage::Feature::MediaAudioCapture) {
|
if (feature == QWebEnginePage::Feature::MediaAudioCapture) {
|
||||||
if (m_virtmicProcess.state() == QProcess::NotRunning) {
|
if (m_virtmicProcess.state() == QProcess::NotRunning) {
|
||||||
qDebug() << "[virtmic] Starting Virtmic with no target to make sure "
|
qDebug(virtmicLog) << "Starting Virtmic with no target to make sure "
|
||||||
"Discord can find all the audio devices";
|
"Discord can find all the audio devices";
|
||||||
m_virtmicProcess.start(QApplication::arguments()[0],
|
m_virtmicProcess.start(QApplication::arguments()[0],
|
||||||
{"--virtmic", "None"});
|
{"--virtmic", "None"});
|
||||||
@@ -119,7 +120,7 @@ QWebEnginePage *DiscordPage::createWindow(QWebEnginePage::WebWindowType type) {
|
|||||||
|
|
||||||
void DiscordPage::stopVirtmic() {
|
void DiscordPage::stopVirtmic() {
|
||||||
if (m_virtmicProcess.state() == QProcess::Running) {
|
if (m_virtmicProcess.state() == QProcess::Running) {
|
||||||
qDebug() << "[virtmic] Stopping Virtmic";
|
qDebug(virtmicLog) << "Stopping Virtmic";
|
||||||
m_virtmicProcess.kill();
|
m_virtmicProcess.kill();
|
||||||
m_virtmicProcess.waitForFinished();
|
m_virtmicProcess.waitForFinished();
|
||||||
}
|
}
|
||||||
@@ -127,7 +128,7 @@ void DiscordPage::stopVirtmic() {
|
|||||||
|
|
||||||
void DiscordPage::startVirtmic(QString target) {
|
void DiscordPage::startVirtmic(QString target) {
|
||||||
if (target != "None") {
|
if (target != "None") {
|
||||||
qDebug() << "[virtmic] Starting Virtmic with target" << target;
|
qDebug(virtmicLog) << "Starting Virtmic with target" << target;
|
||||||
m_virtmicProcess.start(QApplication::arguments()[0], {"--virtmic", target});
|
m_virtmicProcess.start(QApplication::arguments()[0], {"--virtmic", target});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,8 +144,10 @@ void DiscordPage::javaScriptConsoleMessage(
|
|||||||
m_streamDialog.updateTargets();
|
m_streamDialog.updateTargets();
|
||||||
} else if (message == "!discord-screenaudio-stream-stopped") {
|
} else if (message == "!discord-screenaudio-stream-stopped") {
|
||||||
stopVirtmic();
|
stopVirtmic();
|
||||||
|
} else if (message.startsWith("dsa: ")) {
|
||||||
|
qDebug(userscriptLog) << message.mid(5).toUtf8().constData();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "[discord]" << message;
|
qDebug(discordLog) << message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
src/log.cpp
Normal file
6
src/log.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(mainLog, "main");
|
||||||
|
Q_LOGGING_CATEGORY(discordLog, "discord");
|
||||||
|
Q_LOGGING_CATEGORY(userscriptLog, "userscript");
|
||||||
|
Q_LOGGING_CATEGORY(virtmicLog, "virtmic");
|
||||||
8
src/log.h
Normal file
8
src/log.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(mainLog);
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(discordLog);
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(userscriptLog);
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(virtmicLog);
|
||||||
22
src/main.cpp
22
src/main.cpp
@@ -3,11 +3,17 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
QApplication::setApplicationName("discord-screenaudio");
|
QApplication::setApplicationName("discord-screenaudio");
|
||||||
|
QApplication::setWindowIcon(
|
||||||
|
QIcon(":assets/de.shorsh.discord-screenaudio.png"));
|
||||||
QApplication::setApplicationVersion(DISCORD_SCEENAUDIO_VERSION_FULL);
|
QApplication::setApplicationVersion(DISCORD_SCEENAUDIO_VERSION_FULL);
|
||||||
|
QApplication::setDesktopFileName("de.shorsh.discord-screenaudio");
|
||||||
|
|
||||||
|
qSetMessagePattern("[%{category}] %{message}");
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(
|
parser.setApplicationDescription(
|
||||||
@@ -17,16 +23,24 @@ int main(int argc, char *argv[]) {
|
|||||||
QCommandLineOption virtmicOption("virtmic", "Start the Virtual Microphone",
|
QCommandLineOption virtmicOption("virtmic", "Start the Virtual Microphone",
|
||||||
"target");
|
"target");
|
||||||
parser.addOption(virtmicOption);
|
parser.addOption(virtmicOption);
|
||||||
#ifdef DEBUG
|
QCommandLineOption degubOption("remote-debugging",
|
||||||
parser.addOption(QCommandLineOption(
|
"Open Chromium Remote Debugging on port 9222");
|
||||||
"remote-debugging-port", "Chromium Remote Debugging Port", "port"));
|
parser.addOption(degubOption);
|
||||||
#endif
|
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
if (parser.isSet(virtmicOption)) {
|
if (parser.isSet(virtmicOption)) {
|
||||||
Virtmic::start(parser.value(virtmicOption));
|
Virtmic::start(parser.value(virtmicOption));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qputenv("QTWEBENGINE_CHROMIUM_FLAGS",
|
||||||
|
"--enable-features=WebRTCPipeWireCapturer " +
|
||||||
|
qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"));
|
||||||
|
|
||||||
|
if (parser.isSet(degubOption))
|
||||||
|
qputenv("QTWEBENGINE_CHROMIUM_FLAGS",
|
||||||
|
"--remote-debugging-port=9222 " +
|
||||||
|
qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"));
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "virtmic.h"
|
#include "virtmic.h"
|
||||||
|
|
||||||
|
#ifdef KNOTIFICATIONS
|
||||||
|
#include <KNotification>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
@@ -11,6 +15,8 @@
|
|||||||
#include <QSpacerItem>
|
#include <QSpacerItem>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QWebEngineNotification>
|
||||||
|
#include <QWebEngineProfile>
|
||||||
#include <QWebEngineScript>
|
#include <QWebEngineScript>
|
||||||
#include <QWebEngineScriptCollection>
|
#include <QWebEngineScriptCollection>
|
||||||
#include <QWebEngineSettings>
|
#include <QWebEngineSettings>
|
||||||
@@ -30,6 +36,23 @@ void MainWindow::setupWebView() {
|
|||||||
m_webView = new QWebEngineView(this);
|
m_webView = new QWebEngineView(this);
|
||||||
m_webView->setPage(page);
|
m_webView->setPage(page);
|
||||||
|
|
||||||
|
#ifdef KNOTIFICATIONS
|
||||||
|
QWebEngineProfile::defaultProfile()->setNotificationPresenter(
|
||||||
|
[&](std::unique_ptr<QWebEngineNotification> notificationInfo) {
|
||||||
|
KNotification *notification = new KNotification("discordNotification");
|
||||||
|
notification->setTitle(notificationInfo->title());
|
||||||
|
notification->setText(notificationInfo->message());
|
||||||
|
notification->setPixmap(QPixmap::fromImage(notificationInfo->icon()));
|
||||||
|
notification->setDefaultAction("View");
|
||||||
|
connect(notification, &KNotification::defaultActivated,
|
||||||
|
[&, notificationInfo = std::move(notificationInfo)]() {
|
||||||
|
notificationInfo->click();
|
||||||
|
activateWindow();
|
||||||
|
});
|
||||||
|
notification->sendEvent();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
setCentralWidget(m_webView);
|
setCentralWidget(m_webView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,25 @@ StreamDialog::StreamDialog() : QWidget() {
|
|||||||
setAttribute(Qt::WA_QuitOnClose, false);
|
setAttribute(Qt::WA_QuitOnClose, false);
|
||||||
|
|
||||||
auto layout = new QVBoxLayout(this);
|
auto layout = new QVBoxLayout(this);
|
||||||
|
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||||
|
|
||||||
auto targetLabel = new QLabel(this);
|
auto targetLabel = new QLabel(this);
|
||||||
targetLabel->setText("Which app do you want to stream sound from?");
|
targetLabel->setText("Which app do you want to stream sound from?");
|
||||||
layout->addWidget(targetLabel);
|
layout->addWidget(targetLabel);
|
||||||
|
|
||||||
|
auto targetHBox = new QHBoxLayout(this);
|
||||||
|
layout->addLayout(targetHBox);
|
||||||
|
|
||||||
m_targetComboBox = new QComboBox(this);
|
m_targetComboBox = new QComboBox(this);
|
||||||
updateTargets();
|
updateTargets();
|
||||||
layout->addWidget(m_targetComboBox);
|
targetHBox->addWidget(m_targetComboBox);
|
||||||
|
|
||||||
|
auto refreshTargetsButton = new QPushButton(this);
|
||||||
|
refreshTargetsButton->setFixedSize(30, 30);
|
||||||
|
refreshTargetsButton->setIcon(QIcon::fromTheme("view-refresh"));
|
||||||
|
connect(refreshTargetsButton, &QPushButton::clicked, this,
|
||||||
|
&StreamDialog::updateTargets);
|
||||||
|
targetHBox->addWidget(refreshTargetsButton);
|
||||||
|
|
||||||
auto qualityLabel = new QLabel(this);
|
auto qualityLabel = new QLabel(this);
|
||||||
qualityLabel->setText("Stream Quality");
|
qualityLabel->setText("Stream Quality");
|
||||||
@@ -57,7 +68,6 @@ StreamDialog::StreamDialog() : QWidget() {
|
|||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
setWindowTitle("discord-screenaudio Stream Dialog");
|
setWindowTitle("discord-screenaudio Stream Dialog");
|
||||||
setFixedSize(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamDialog::startStream() {
|
void StreamDialog::startStream() {
|
||||||
@@ -70,9 +80,17 @@ void StreamDialog::startStream() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StreamDialog::updateTargets() {
|
void StreamDialog::updateTargets() {
|
||||||
|
auto lastTarget = m_targetComboBox->currentText();
|
||||||
|
|
||||||
m_targetComboBox->clear();
|
m_targetComboBox->clear();
|
||||||
m_targetComboBox->addItem("None");
|
m_targetComboBox->addItem("[None]");
|
||||||
|
m_targetComboBox->addItem("[All Desktop Audio]");
|
||||||
for (auto target : Virtmic::getTargets()) {
|
for (auto target : Virtmic::getTargets()) {
|
||||||
m_targetComboBox->addItem(target);
|
m_targetComboBox->addItem(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_targetComboBox->findText(lastTarget) != -1)
|
||||||
|
m_targetComboBox->setCurrentText(lastTarget);
|
||||||
|
else
|
||||||
|
m_targetComboBox->setCurrentText("[All Desktop Audio]");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#include "virtmic.h"
|
#include "virtmic.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#include <rohrkabel/loop/main.hpp>
|
#include <rohrkabel/loop/main.hpp>
|
||||||
#include <rohrkabel/registry/registry.hpp>
|
#include <rohrkabel/registry/registry.hpp>
|
||||||
|
|
||||||
namespace Virtmic {
|
namespace Virtmic {
|
||||||
|
|
||||||
|
const QStringList EXCLUDE_TARGETS{"Chromium input", "discord-screenaudio"};
|
||||||
|
|
||||||
QVector<QString> getTargets() {
|
QVector<QString> getTargets() {
|
||||||
auto main_loop = pipewire::main_loop();
|
auto main_loop = pipewire::main_loop();
|
||||||
auto context = pipewire::context(main_loop);
|
auto context = pipewire::context(main_loop);
|
||||||
@@ -19,10 +22,10 @@ QVector<QString> getTargets() {
|
|||||||
if (global.type == pipewire::node::type) {
|
if (global.type == pipewire::node::type) {
|
||||||
auto node = reg.bind<pipewire::node>(global.id);
|
auto node = reg.bind<pipewire::node>(global.id);
|
||||||
auto info = node.info();
|
auto info = node.info();
|
||||||
|
auto name = QString::fromStdString(info.props["application.name"]);
|
||||||
|
|
||||||
if (info.props.count("node.name")) {
|
if (name != "" && !EXCLUDE_TARGETS.contains(name) &&
|
||||||
auto name = QString::fromStdString(info.props["node.name"]);
|
!targets.contains(name)) {
|
||||||
if (!targets.contains(name))
|
|
||||||
targets.append(name);
|
targets.append(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,20 +67,24 @@ void start(QString _target) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto &parent = nodes.at(parent_id);
|
auto &parent = nodes.at(parent_id);
|
||||||
|
auto name = parent.props["application.name"];
|
||||||
|
|
||||||
if (parent.props["node.name"].find(target) != std::string::npos) {
|
if (name == target ||
|
||||||
std::cout << "[virtmic] "
|
(target == "[All Desktop Audio]" &&
|
||||||
<< "Link : " << target << ":" << port_id << " -> ";
|
!EXCLUDE_TARGETS.contains(QString::fromStdString(name)))) {
|
||||||
|
auto fl = port.info().props["audio.channel"] == "FL";
|
||||||
if (port.info().props["audio.channel"] == "FL") {
|
links.emplace(
|
||||||
links.emplace(port_id, core.create<pipewire::link_factory>(
|
port_id,
|
||||||
{virt_fl->info().id, port_id}));
|
core.create<pipewire::link_factory>(
|
||||||
std::cout << "[virtmic] " << virt_fl->info().id << std::endl;
|
{fl ? virt_fl->info().id : virt_fr->info().id, port_id}));
|
||||||
} else {
|
qDebug(virtmicLog) << QString("Link: %1:%2 -> %3")
|
||||||
links.emplace(port_id, core.create<pipewire::link_factory>(
|
.arg(QString::fromStdString(
|
||||||
{virt_fr->info().id, port_id}));
|
parent.props["application.name"]))
|
||||||
std::cout << "[virtmic] " << virt_fr->info().id << std::endl;
|
.arg(port_id)
|
||||||
}
|
.arg(fl ? virt_fl->info().id
|
||||||
|
: virt_fr->info().id)
|
||||||
|
.toUtf8()
|
||||||
|
.data();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -93,7 +100,7 @@ void start(QString _target) {
|
|||||||
pipewire::node::type, pipewire::node::version,
|
pipewire::node::type, pipewire::node::version,
|
||||||
pipewire::update_strategy::none);
|
pipewire::update_strategy::none);
|
||||||
|
|
||||||
if (target == "None") {
|
if (target == "[None]") {
|
||||||
while (true) {
|
while (true) {
|
||||||
main_loop.run();
|
main_loop.run();
|
||||||
}
|
}
|
||||||
@@ -105,9 +112,13 @@ void start(QString _target) {
|
|||||||
[&](const pipewire::global &global) {
|
[&](const pipewire::global &global) {
|
||||||
if (global.type == pipewire::node::type) {
|
if (global.type == pipewire::node::type) {
|
||||||
auto node = reg.bind<pipewire::node>(global.id);
|
auto node = reg.bind<pipewire::node>(global.id);
|
||||||
std::cout << "[virtmic] "
|
if (!node.info().props.count("application.name"))
|
||||||
<< "Added : " << node.info().props["node.name"]
|
return;
|
||||||
<< std::endl;
|
qDebug(virtmicLog) << QString("Added: %1")
|
||||||
|
.arg(QString::fromStdString(
|
||||||
|
node.info().props["application.name"]))
|
||||||
|
.toUtf8()
|
||||||
|
.data();
|
||||||
|
|
||||||
if (!nodes.count(global.id)) {
|
if (!nodes.count(global.id)) {
|
||||||
nodes.emplace(global.id, node.info());
|
nodes.emplace(global.id, node.info());
|
||||||
@@ -141,8 +152,11 @@ void start(QString _target) {
|
|||||||
[&](const std::uint32_t id) {
|
[&](const std::uint32_t id) {
|
||||||
if (nodes.count(id)) {
|
if (nodes.count(id)) {
|
||||||
auto info = nodes.at(id);
|
auto info = nodes.at(id);
|
||||||
std::cout << "[virtmic] "
|
qDebug(virtmicLog) << QString("Removed: %1")
|
||||||
<< "Removed: " << info.props["node.name"] << std::endl;
|
.arg(QString::fromStdString(
|
||||||
|
info.props["application.name"].data()))
|
||||||
|
.toUtf8()
|
||||||
|
.data();
|
||||||
nodes.erase(id);
|
nodes.erase(id);
|
||||||
}
|
}
|
||||||
if (ports.count(id)) {
|
if (ports.count(id)) {
|
||||||
|
|||||||
@@ -138,11 +138,12 @@ function(determine_version source_dir var_prefix)
|
|||||||
# | exact tag | 0.9.0 |
|
# | exact tag | 0.9.0 |
|
||||||
# | exact tag, dirty | 0.9.0+git20180604 |
|
# | exact tag, dirty | 0.9.0+git20180604 |
|
||||||
# | after tag | 0.9.0+git20180604.1.085039f |
|
# | after tag | 0.9.0+git20180604.1.085039f |
|
||||||
# | no tag, version.txt | 0.9.0+git20180604.2ee02af |
|
# | no tag, version.txt | 0.9.0 |
|
||||||
# | no tag, no version.txt| 0.0.0+git20180604.2ee02af |
|
# | no tag, no version.txt| 0.0.0+git20180604.2ee02af |
|
||||||
string(TIMESTAMP date "%Y%m%d" UTC)
|
string(TIMESTAMP date "%Y%m%d" UTC)
|
||||||
set(version_suffix "")
|
set(version_suffix "")
|
||||||
if (NOT ${local_prefix}_VERSION_NCOMMITS EQUAL 0)
|
if (has_version_txt)
|
||||||
|
elseif (NOT ${local_prefix}_VERSION_NCOMMITS EQUAL 0)
|
||||||
# 0.9.0+git20150604.4.289818b
|
# 0.9.0+git20150604.4.289818b
|
||||||
string(APPEND version_suffix "+git${date}.${${local_prefix}_VERSION_NCOMMITS}.${${local_prefix}_VERSION_GIT_REV}")
|
string(APPEND version_suffix "+git${date}.${${local_prefix}_VERSION_NCOMMITS}.${${local_prefix}_VERSION_GIT_REV}")
|
||||||
elseif ((NOT has_release_tag) AND ((NOT has_version_txt) OR ("${base_version}" STREQUAL "0.0.0") OR (NOT "${revision}" STREQUAL "")))
|
elseif ((NOT has_release_tag) AND ((NOT has_version_txt) OR ("${base_version}" STREQUAL "0.0.0") OR (NOT "${revision}" STREQUAL "")))
|
||||||
|
|||||||
Reference in New Issue
Block a user