Compare commits

..

1 Commits

Author SHA1 Message Date
Malte Jürgens
bdabf68c9b add chromium flags for hardware acceleration 2022-10-15 20:28:38 +02:00
12 changed files with 117 additions and 196 deletions

View File

@@ -13,27 +13,24 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
string(TIMESTAMP TIMESTAMP %s) string(TIMESTAMP TIMESTAMP %s)
# set(CMAKE_AUTOUIC ON) # set(CMAKE_AUTOUIC ON)
find_package(Qt5 COMPONENTS Widgets) find_package(Qt5 CONFIG REQUIRED COMPONENTS
if (Qt5_FOUND) Widgets
find_package(Qt5 CONFIG REQUIRED COMPONENTS Widgets WebEngineWidgets) WebEngineWidgets
)
find_package(KF5Notifications) find_package(KF5Notifications)
if(KF5Notifications_FOUND) if(KF5Notifications_FOUND)
add_definitions( -DKNOTIFICATIONS ) add_definitions( -DKNOTIFICATIONS )
endif() endif()
find_package(KF5XmlGui) find_package(KF5XmlGui)
if(KF5XmlGui_FOUND) if(KF5XmlGui_FOUND)
add_definitions( -DKXMLGUI ) add_definitions( -DKXMLGUI )
endif() endif()
find_package(KF5GlobalAccel) find_package(KF5GlobalAccel)
if(KF5GlobalAccel_FOUND) if(KF5GlobalAccel_FOUND)
add_definitions( -DKGLOBALACCEL ) add_definitions( -DKGLOBALACCEL )
endif()
else()
message(WARNING "Qt 5 was not found on your system and Qt 6 will be used. You will not be able to use any features using KDE Frameworks.")
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets WebEngineWidgets)
endif() endif()
set(discord-screenaudio_SRC set(discord-screenaudio_SRC
@@ -69,7 +66,7 @@ add_subdirectory(submodules/rohrkabel)
add_executable(discord-screenaudio ${discord-screenaudio_SRC}) add_executable(discord-screenaudio ${discord-screenaudio_SRC})
target_link_libraries(discord-screenaudio Qt::Widgets Qt::WebEngineWidgets rohrkabel) target_link_libraries(discord-screenaudio Qt5::Widgets Qt5::WebEngineWidgets rohrkabel)
if(KF5Notifications_FOUND) if(KF5Notifications_FOUND)
target_link_libraries(discord-screenaudio KF5::Notifications) target_link_libraries(discord-screenaudio KF5::Notifications)

View File

@@ -11,7 +11,7 @@ Unlike a lot of other solutions, the audio here is directly fed into the
screenshare and not passed to the user microphone screenshare and not passed to the user microphone
([see explanation](#how-it-works)). ([see explanation](#how-it-works)).
![Screenshot_20221211_185028](https://user-images.githubusercontent.com/48161361/206920213-58a8091a-d8f9-4bb7-ae3d-3f8581b84d24.png) ![Screenshot_20220925_112945](https://user-images.githubusercontent.com/48161361/192137080-33466cf7-8c56-4373-90c6-01ea74b6fb83.png)
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
Discord client. Rather, it should be used in addition to the original client in Discord client. Rather, it should be used in addition to the original client in
@@ -50,8 +50,6 @@ You have multiple options:
### Requirements ### Requirements
- Basic building tools - Basic building tools
- An up-to-date system (I can't guarantee that it works on Debian or Ubuntu
20/21)
- CMake - CMake
- Qt5 and QtWebEngine - Qt5 and QtWebEngine
- **PipeWire** (it currently doesn't work with PulseAudio) - **PipeWire** (it currently doesn't work with PulseAudio)
@@ -59,7 +57,7 @@ You have multiple options:
- _Kf5Notifications (optional, for better notifications)_ - _Kf5Notifications (optional, for better notifications)_
- _KXMLGui and KGlobalAccel (optional, for keybinds)_ - _KXMLGui and KGlobalAccel (optional, for keybinds)_
With apt: On Debian:
`apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev libkf5notifications-dev libkf5xmlgui-dev libkf5globalaccel-dev pkg-config libpipewire-0.3-dev git` `apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev libkf5notifications-dev libkf5xmlgui-dev libkf5globalaccel-dev pkg-config libpipewire-0.3-dev git`
### Building ### Building

View File

@@ -4,7 +4,6 @@
<metadata_license>CC0-1.0</metadata_license> <metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0+</project_license> <project_license>GPL-3.0+</project_license>
<name>discord-screenaudio</name> <name>discord-screenaudio</name>
<developer_name>Malte Jürgens</developer_name>
<releases> <releases>
<release version="${DISCORD_SCEENAUDIO_VERSION_FULL}" timestamp="${TIMESTAMP}" /> <release version="${DISCORD_SCEENAUDIO_VERSION_FULL}" timestamp="${TIMESTAMP}" />
</releases> </releases>

View File

@@ -25,7 +25,7 @@ const getAudioDevice = async (nameOfAudioDevice) => {
return audioDevice; return audioDevice;
}; };
function setGetDisplayMedia(video = true, overrideArgs = undefined) { function setGetDisplayMedia(overrideArgs = undefined) {
const getDisplayMedia = async (...args) => { const getDisplayMedia = async (...args) => {
var id; var id;
try { try {
@@ -63,7 +63,6 @@ function setGetDisplayMedia(video = true, overrideArgs = undefined) {
: args || [{ video: true, audio: true }]) : args || [{ video: true, audio: true }])
); );
gdm.addTrack(track); gdm.addTrack(track);
if (!video) for (const track of gdm.getVideoTracks()) track.enabled = false;
return gdm; return gdm;
}; };
navigator.mediaDevices.getDisplayMedia = getDisplayMedia; navigator.mediaDevices.getDisplayMedia = getDisplayMedia;
@@ -112,16 +111,9 @@ setInterval(() => {
const initialDisplay = el.style.display; const initialDisplay = el.style.display;
window.discordScreenaudioStartStream = ( window.discordScreenaudioStartStream = (width, height, frameRate) => {
video, window.discordScreenaudioResolutionString = `${height}p ${frameRate}FPS`;
width, setGetDisplayMedia({
height,
frameRate
) => {
window.discordScreenaudioResolutionString = video
? `${height}p ${frameRate}FPS`
: "Audio Only";
setGetDisplayMedia(video, {
audio: true, audio: true,
video: { width, height, frameRate }, video: { width, height, frameRate },
}); });
@@ -171,7 +163,7 @@ setInterval(() => {
document document
.getElementById("keybinds-tab") .getElementById("keybinds-tab")
?.getElementsByClassName( ?.getElementsByClassName(
"container-3jbRo5 info-1hMolH browserNotice-1u-Y5o" "container-3jbRo5 info-1hMolH fontSize16-3zr6Io browserNotice-1u-Y5o"
).length ).length
) { ) {
const el = document const el = document
@@ -191,28 +183,14 @@ setInterval(() => {
el.appendChild(div); el.appendChild(div);
} }
const buttonContainer = const muteBtn = document.getElementsByClassName(
document.getElementsByClassName("container-YkUktl")[0]; "button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
if (!buttonContainer) { )[0];
console.log( window.discordScreenaudioToggleMute = () => muteBtn.click();
"dsa: Cannot locate Mute/Deafen/Settings button container, please report this on GitHub" const deafenBtn = document.getElementsByClassName(
); "button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
} )[1];
window.discordScreenaudioToggleDeafen = () => deafenBtn.click();
const muteBtn = buttonContainer
? buttonContainer.getElementsByClassName(
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
)[0]
: null;
window.discordScreenaudioToggleMute = () => muteBtn && muteBtn.click();
const deafenBtn = buttonContainer
? buttonContainer.getElementsByClassName(
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
)[1]
: null;
window.discordScreenaudioToggleDeafen = () => deafenBtn && deafenBtn.click();
if (window.discordScreenaudioResolutionString) { if (window.discordScreenaudioResolutionString) {
for (const el of document.getElementsByClassName( for (const el of document.getElementsByClassName(

View File

@@ -186,8 +186,10 @@ void DiscordPage::stopVirtmic() {
} }
void DiscordPage::startVirtmic(QString target) { void DiscordPage::startVirtmic(QString target) {
qDebug(virtmicLog) << "Starting Virtmic with target" << target; if (target != "None") {
m_virtmicProcess.start(QApplication::arguments()[0], {"--virtmic", target}); qDebug(virtmicLog) << "Starting Virtmic with target" << target;
m_virtmicProcess.start(QApplication::arguments()[0], {"--virtmic", target});
}
} }
void DiscordPage::javaScriptConsoleMessage( void DiscordPage::javaScriptConsoleMessage(
@@ -228,18 +230,16 @@ void DiscordPage::javaScriptConsoleMessage(
} }
} }
void DiscordPage::startStream(bool video, bool audio, uint width, uint height, void DiscordPage::startStream(QString target, uint width, uint height,
uint frameRate, QString target) { uint frameRate) {
stopVirtmic(); stopVirtmic();
startVirtmic(audio ? target : "[None]"); startVirtmic(target);
// Wait a bit for the virtmic to start // Wait a bit for the virtmic to start
QTimer::singleShot(200, [=]() { QTimer::singleShot(target == "None" ? 0 : 200, [=]() {
runJavaScript( runJavaScript(QString("window.discordScreenaudioStartStream(%1, %2, %3);")
QString("window.discordScreenaudioStartStream(%1, %2, %3, %4);") .arg(width)
.arg(video) .arg(height)
.arg(video ? width : 32) .arg(frameRate));
.arg(video ? height : 16)
.arg(video ? frameRate : 1));
}); });
} }

View File

@@ -47,8 +47,7 @@ private:
private Q_SLOTS: private Q_SLOTS:
void featurePermissionRequested(const QUrl &securityOrigin, void featurePermissionRequested(const QUrl &securityOrigin,
QWebEnginePage::Feature feature); QWebEnginePage::Feature feature);
void startStream(bool video, bool audio, uint width, uint height, void startStream(QString target, uint width, uint height, uint frameRate);
uint frameRate, QString target);
}; };
// Will immediately get destroyed again but is needed for navigation to // Will immediately get destroyed again but is needed for navigation to

View File

@@ -30,9 +30,6 @@ int main(int argc, char *argv[]) {
QCommandLineOption degubOption("remote-debugging", QCommandLineOption degubOption("remote-debugging",
"Open Chromium Remote Debugging on port 9222"); "Open Chromium Remote Debugging on port 9222");
parser.addOption(degubOption); parser.addOption(degubOption);
QCommandLineOption notifySendOption(
"notify-send", "Use notify-send instead of QT/KF5 notifications");
parser.addOption(notifySendOption);
parser.process(app); parser.process(app);
@@ -41,6 +38,8 @@ int main(int argc, char *argv[]) {
} }
qputenv("QTWEBENGINE_CHROMIUM_FLAGS", qputenv("QTWEBENGINE_CHROMIUM_FLAGS",
"--ignore-gpu-blacklist --enable-gpu-rasterization "
"--enable-native-gpu-memory-buffers --num-raster-threads=4 "
"--enable-features=WebRTCPipeWireCapturer " + "--enable-features=WebRTCPipeWireCapturer " +
qgetenv("QTWEBENGINE_CHROMIUM_FLAGS")); qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"));
@@ -49,7 +48,7 @@ int main(int argc, char *argv[]) {
"--remote-debugging-port=9222 " + "--remote-debugging-port=9222 " +
qgetenv("QTWEBENGINE_CHROMIUM_FLAGS")); qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"));
MainWindow w(parser.isSet(notifySendOption)); MainWindow w;
w.show(); w.show();
return app.exec(); return app.exec();

View File

@@ -24,11 +24,9 @@
MainWindow *MainWindow::m_instance = nullptr; MainWindow *MainWindow::m_instance = nullptr;
MainWindow::MainWindow(bool useNotifySend, QWidget *parent) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
: QMainWindow(parent) {
assert(MainWindow::m_instance == nullptr); assert(MainWindow::m_instance == nullptr);
MainWindow::m_instance = this; MainWindow::m_instance = this;
m_useNotifySend = useNotifySend;
setupWebView(); setupWebView();
resize(1000, 700); resize(1000, 700);
showMaximized(); showMaximized();
@@ -42,36 +40,22 @@ void MainWindow::setupWebView() {
m_webView = new QWebEngineView(this); m_webView = new QWebEngineView(this);
m_webView->setPage(page); m_webView->setPage(page);
if (m_useKF5Notifications || m_useNotifySend)
QWebEngineProfile::defaultProfile()->setNotificationPresenter(
[&](std::unique_ptr<QWebEngineNotification> notificationInfo) {
if (m_useNotifySend) {
auto title = notificationInfo->title();
auto message = notificationInfo->message();
auto image_path =
QString("/tmp/discord-screenaudio-%1.png").arg(title);
notificationInfo->icon().save(image_path);
QProcess::execute("notify-send",
{"--icon", image_path, "--app-name",
"discord-screenaudio", title, message});
} else if (m_useKF5Notifications) {
#ifdef KNOTIFICATIONS #ifdef KNOTIFICATIONS
KNotification *notification = QWebEngineProfile::defaultProfile()->setNotificationPresenter(
new KNotification("discordNotification"); [&](std::unique_ptr<QWebEngineNotification> notificationInfo) {
notification->setTitle(notificationInfo->title()); KNotification *notification = new KNotification("discordNotification");
notification->setText(notificationInfo->message()); notification->setTitle(notificationInfo->title());
notification->setPixmap( notification->setText(notificationInfo->message());
QPixmap::fromImage(notificationInfo->icon())); notification->setPixmap(QPixmap::fromImage(notificationInfo->icon()));
notification->setDefaultAction("View"); notification->setDefaultAction("View");
connect(notification, &KNotification::defaultActivated, connect(notification, &KNotification::defaultActivated,
[&, notificationInfo = std::move(notificationInfo)]() { [&, notificationInfo = std::move(notificationInfo)]() {
notificationInfo->click(); notificationInfo->click();
activateWindow(); activateWindow();
}); });
notification->sendEvent(); notification->sendEvent();
});
#endif #endif
}
});
setCentralWidget(m_webView); setCentralWidget(m_webView);
} }

View File

@@ -14,7 +14,7 @@ class MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(bool useNotifySend = false, QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
static MainWindow *instance(); static MainWindow *instance();
private: private:
@@ -25,12 +25,6 @@ private:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
bool m_wasMaximized; bool m_wasMaximized;
static MainWindow *m_instance; static MainWindow *m_instance;
bool m_useNotifySend;
#ifdef KNOTIFICATIONS
bool m_useKF5Notifications = true;
#else
bool m_useKF5Notifications = false;
#endif
private Q_SLOTS: private Q_SLOTS:
void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest);

View File

@@ -12,96 +12,70 @@
StreamDialog::StreamDialog() : QWidget() { 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);
layout->setSizeConstraint(QLayout::SetFixedSize);
m_videoGroupBox = new QGroupBox(this); auto targetLabel = new QLabel(this);
m_videoGroupBox->setTitle("Video"); targetLabel->setText("Which app do you want to stream sound from?");
m_videoGroupBox->setCheckable(true); layout->addWidget(targetLabel);
layout->addWidget(m_videoGroupBox);
{ auto targetHBox = new QHBoxLayout(this);
auto videoLayout = new QVBoxLayout(this); layout->addLayout(targetHBox);
m_videoGroupBox->setLayout(videoLayout);
auto resolutionLabel = new QLabel(this); m_targetComboBox = new QComboBox(this);
resolutionLabel->setText("Resolution"); updateTargets();
videoLayout->addWidget(resolutionLabel); targetHBox->addWidget(m_targetComboBox);
m_resolutionComboBox = new QComboBox(this); auto refreshTargetsButton = new QPushButton(this);
m_resolutionComboBox->addItem("2160p", "3840x2160"); refreshTargetsButton->setFixedSize(30, 30);
m_resolutionComboBox->addItem("1440p", "2560x1440"); refreshTargetsButton->setIcon(QIcon::fromTheme("view-refresh"));
m_resolutionComboBox->addItem("1080p", "1920x1080"); connect(refreshTargetsButton, &QPushButton::clicked, this,
m_resolutionComboBox->addItem("720p", "1280x720"); &StreamDialog::updateTargets);
m_resolutionComboBox->addItem("480p", "854x480"); targetHBox->addWidget(refreshTargetsButton);
m_resolutionComboBox->addItem("360p", "640x360");
m_resolutionComboBox->addItem("240p", "426x240");
m_resolutionComboBox->setCurrentText("720p");
videoLayout->addWidget(m_resolutionComboBox);
auto framerateLabel = new QLabel(this); auto qualityLabel = new QLabel(this);
framerateLabel->setText("Framerate"); qualityLabel->setText("Stream Quality");
videoLayout->addWidget(framerateLabel); layout->addWidget(qualityLabel);
m_framerateComboBox = new QComboBox(this); auto qualityHBox = new QHBoxLayout(this);
m_framerateComboBox->addItem("144 FPS", 144); layout->addLayout(qualityHBox);
m_framerateComboBox->addItem("60 FPS", 60);
m_framerateComboBox->addItem("30 FPS", 30);
m_framerateComboBox->addItem("15 FPS", 15);
m_framerateComboBox->addItem("5 FPS", 5);
m_framerateComboBox->setCurrentText("30 FPS");
videoLayout->addWidget(m_framerateComboBox);
}
m_audioGroupBox = new QGroupBox(this); m_qualityResolutionComboBox = new QComboBox(this);
m_audioGroupBox->setCheckable(true); m_qualityResolutionComboBox->addItem("2160p", "3840x2160");
m_audioGroupBox->setTitle("Audio"); m_qualityResolutionComboBox->addItem("1440p", "2560x1440");
layout->addWidget(m_audioGroupBox); m_qualityResolutionComboBox->addItem("1080p", "1920x1080");
m_qualityResolutionComboBox->addItem("720p", "1280x720");
m_qualityResolutionComboBox->addItem("480p", "854x480");
m_qualityResolutionComboBox->addItem("360p", "640x360");
m_qualityResolutionComboBox->addItem("240p", "426x240");
m_qualityResolutionComboBox->setCurrentText("720p");
qualityHBox->addWidget(m_qualityResolutionComboBox);
{ m_qualityFPSComboBox = new QComboBox(this);
auto audioLayout = new QVBoxLayout(this); m_qualityFPSComboBox->addItem("144 FPS", 144);
m_audioGroupBox->setLayout(audioLayout); m_qualityFPSComboBox->addItem("60 FPS", 60);
m_qualityFPSComboBox->addItem("30 FPS", 30);
m_qualityFPSComboBox->addItem("15 FPS", 15);
m_qualityFPSComboBox->addItem("5 FPS", 5);
m_qualityFPSComboBox->setCurrentText("30 FPS");
qualityHBox->addWidget(m_qualityFPSComboBox);
auto targetLabel = new QLabel(this); auto button = new QPushButton(this);
targetLabel->setText("Audio Source"); button->setText("Start Stream");
audioLayout->addWidget(targetLabel); connect(button, &QPushButton::clicked, this, &StreamDialog::startStream);
layout->addWidget(button, Qt::AlignRight | Qt::AlignBottom);
{ setLayout(layout);
auto targetLayout = new QHBoxLayout(this);
audioLayout->addLayout(targetLayout);
m_targetComboBox = new QComboBox(this);
updateTargets();
targetLayout->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);
targetLayout->addWidget(refreshTargetsButton);
}
}
auto button = new QPushButton(this);
button->setText("Start Stream");
connect(button, &QPushButton::clicked, this, &StreamDialog::startStream);
layout->addWidget(button, Qt::AlignRight | Qt::AlignBottom);
setLayout(layout);
}
setWindowTitle("discord-screenaudio Stream Dialog"); setWindowTitle("discord-screenaudio Stream Dialog");
} }
void StreamDialog::startStream() { void StreamDialog::startStream() {
auto resolution = m_resolutionComboBox->currentData().toString().split('x'); auto resolution =
emit requestedStreamStart(m_videoGroupBox->isChecked(), m_qualityResolutionComboBox->currentData().toString().split('x');
m_audioGroupBox->isChecked(), emit requestedStreamStart(m_targetComboBox->currentText(),
resolution[0].toUInt(), resolution[1].toUInt(), resolution[0].toUInt(), resolution[1].toUInt(),
m_framerateComboBox->currentData().toUInt(), m_qualityFPSComboBox->currentData().toUInt());
m_targetComboBox->currentText());
setHidden(true); setHidden(true);
} }
@@ -109,6 +83,7 @@ void StreamDialog::updateTargets() {
auto lastTarget = m_targetComboBox->currentText(); auto lastTarget = m_targetComboBox->currentText();
m_targetComboBox->clear(); m_targetComboBox->clear();
m_targetComboBox->addItem("[None]");
m_targetComboBox->addItem("[All Desktop Audio]"); m_targetComboBox->addItem("[All Desktop Audio]");
for (auto target : Virtmic::getTargets()) { for (auto target : Virtmic::getTargets()) {
m_targetComboBox->addItem(target); m_targetComboBox->addItem(target);

View File

@@ -2,7 +2,6 @@
#include <QComboBox> #include <QComboBox>
#include <QDialog> #include <QDialog>
#include <QGroupBox>
#include <QWidget> #include <QWidget>
class StreamDialog : public QWidget { class StreamDialog : public QWidget {
@@ -13,14 +12,12 @@ public:
private: private:
QComboBox *m_targetComboBox; QComboBox *m_targetComboBox;
QComboBox *m_resolutionComboBox; QComboBox *m_qualityResolutionComboBox;
QComboBox *m_framerateComboBox; QComboBox *m_qualityFPSComboBox;
QGroupBox *m_videoGroupBox;
QGroupBox *m_audioGroupBox;
Q_SIGNALS: Q_SIGNALS:
void requestedStreamStart(bool video, bool audio, uint width, uint height, void requestedStreamStart(QString target, uint width, uint height,
uint frameRate, QString target); uint frameRate);
public Q_SLOTS: public Q_SLOTS:
void updateTargets(); void updateTargets();

1
submodules/Vencord Submodule

Submodule submodules/Vencord added at 0d996633f2