Compare commits

..

1 Commits

Author SHA1 Message Date
Malte Jürgens
3e939c4592 work 2023-03-19 14:57:57 +01:00
12 changed files with 70 additions and 158 deletions

View File

@@ -45,7 +45,7 @@ set(discord-screenaudio_SRC
src/log.cpp src/log.cpp
src/userscript.cpp src/userscript.cpp
src/centralwidget.cpp src/centralwidget.cpp
src/localserver.cpp src/dependencycheck.cpp
resources.qrc resources.qrc
) )

View File

@@ -62,9 +62,6 @@ You have multiple options:
With apt: With apt:
`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`
With dnf:
`dnf install @development-tools cmake qt5-qtbase-devel qt5-qtwebengine-devel kf5-knotifications-devel kf5-kxmlgui-devel kf5-kglobalaccel-devel pkgconfig pipewire-devel git`
### Building ### Building
First, clone the repository: First, clone the repository:

View File

@@ -1,14 +1,12 @@
navigator.mediaDevices.chromiumGetDisplayMedia = navigator.mediaDevices.chromiumGetDisplayMedia =
navigator.mediaDevices.getDisplayMedia; navigator.mediaDevices.getDisplayMedia;
navigator.mediaDevices.chromiumGetUserMedia =
navigator.mediaDevices.getUserMedia;
function sleep(ms) { function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
const getAudioDevice = async (nameOfAudioDevice) => { const getAudioDevice = async (nameOfAudioDevice) => {
await navigator.mediaDevices.chromiumGetUserMedia({ await navigator.mediaDevices.getUserMedia({
audio: true, audio: true,
}); });
let audioDevice; let audioDevice;
@@ -25,16 +23,6 @@ const getAudioDevice = async (nameOfAudioDevice) => {
return audioDevice; return audioDevice;
}; };
function setGetUserMedia() {
const getUserMedia = async (constraints) => {
return await navigator.mediaDevices.chromiumGetUserMedia({
video: constraints?.video || false,
audio: { ...constraints?.audio, autoGainControl },
});
};
navigator.mediaDevices.getUserMedia = getUserMedia;
}
function setGetDisplayMedia(video = true, overrideArgs = undefined) { function setGetDisplayMedia(video = true, overrideArgs = undefined) {
const getDisplayMedia = async (...args) => { const getDisplayMedia = async (...args) => {
var id; var id;
@@ -46,27 +34,26 @@ function setGetDisplayMedia(video = true, overrideArgs = undefined) {
} catch (error) { } catch (error) {
id = "default"; id = "default";
} }
let captureSystemAudioStream = let captureSystemAudioStream = await navigator.mediaDevices.getUserMedia({
await navigator.mediaDevices.chromiumGetUserMedia({ audio: {
audio: { // We add our audio constraints here, to get a list of supported constraints use navigator.mediaDevices.getSupportedConstraints();
// We add our audio constraints here, to get a list of supported constraints use navigator.mediaDevices.getSupportedConstraints(); // We must capture a microphone, we use default since its the only deviceId that is the same for every Chromium user
// We must capture a microphone, we use default since its the only deviceId that is the same for every Chromium user deviceId: {
deviceId: { exact: id,
exact: id,
},
// We want auto gain control, noise cancellation and noise suppression disabled so that our stream won't sound bad
autoGainControl: false,
echoCancellation: false,
noiseSuppression: false,
// By default Chromium sets channel count for audio devices to 1, we want it to be stereo in case we find a way for Discord to accept stereo screenshare too
channelCount: 2,
// You can set more audio constraints here, bellow are some examples
//latency: 0,
//sampleRate: 48000,
//sampleSize: 16,
//volume: 1.0
}, },
}); // We want auto gain control, noise cancellation and noise suppression disabled so that our stream won't sound bad
autoGainControl: false,
echoCancellation: false,
noiseSuppression: false,
// By default Chromium sets channel count for audio devices to 1, we want it to be stereo in case we find a way for Discord to accept stereo screenshare too
channelCount: 2,
// You can set more audio constraints here, bellow are some examples
//latency: 0,
//sampleRate: 48000,
//sampleSize: 16,
//volume: 1.0
},
});
let [track] = captureSystemAudioStream.getAudioTracks(); let [track] = captureSystemAudioStream.getAudioTracks();
const gdm = await navigator.mediaDevices.chromiumGetDisplayMedia( const gdm = await navigator.mediaDevices.chromiumGetDisplayMedia(
...(overrideArgs ...(overrideArgs
@@ -81,7 +68,6 @@ function setGetDisplayMedia(video = true, overrideArgs = undefined) {
} }
setGetDisplayMedia(); setGetDisplayMedia();
setGetUserMedia();
let userscript; let userscript;
let muteBtn; let muteBtn;
@@ -90,7 +76,6 @@ let streamStartBtn;
let streamStartBtnInitialDisplay; let streamStartBtnInitialDisplay;
let streamStartBtnClone; let streamStartBtnClone;
let resolutionString; let resolutionString;
let autoGainControl = true;
const clonedElements = []; const clonedElements = [];
const hiddenElements = []; const hiddenElements = [];
let wasStreamActive = false; let wasStreamActive = false;
@@ -174,10 +159,6 @@ function main() {
streamStartBtnClone.remove(); streamStartBtnClone.remove();
}); });
userscript.getPref("disableAutomaticGain", false).then((disabled) => {
autoGainControl = !disabled;
});
function updateUserstyles() { function updateUserstyles() {
userscript.log("Loading userstyles..."); userscript.log("Loading userstyles...");
userscript.loadingMessage = "Loading userstyles..."; userscript.loadingMessage = "Loading userstyles...";
@@ -387,29 +368,5 @@ function main() {
} }
} }
} }
for (const el of document.getElementsByClassName("sensitivity-3A7Gs9")) {
if (
el.getElementsByTagName("div").length > 0 &&
!document.getElementById("discord-screenaudio-gaintoggle")
) {
const toggle = createSwitch(
"Disable automatic gain",
await userscript.getPref("disableAutomaticGain", false),
async (disabled) => {
await userscript.setPref("disableAutomaticGain", disabled);
autoGainControl = !disabled;
setGetUserMedia();
if (disabled)
userscript.showInformation(
"discord-screenaudio",
"If you are currently in a call, this setting may only take effect after you rejoin the call or restart discord-screenaudio."
);
}
);
toggle.id = "discord-screenaudio-gaintoggle";
el.getElementsByTagName("div")[0].appendChild(toggle);
}
}
}, 500); }, 500);
} }

10
src/dependencycheck.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include "dependencycheck.h"
#include "pipewire-0.3/pipewire/version.h"
#include <QMessageBox>
void checkDependencies() {
QString versionPipewire(pw_get_library_version());
QMessageBox::information(nullptr, "Dependency Check",
QString("Pipewire: v%1").arg(versionPipewire));
}

3
src/dependencycheck.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void checkDependencies();

View File

@@ -282,11 +282,10 @@ void DiscordPage::javaScriptConsoleMessage(
ansi += "\033[" + cssAnsiColorMap[color] + "m"; ansi += "\033[" + cssAnsiColorMap[color] + "m";
} }
} }
if (endOfStyles < lines.length()) qDebug(discordLog) << (ansi + lines[0].trimmed() + "\033[0m " +
qDebug(discordLog) << (ansi + lines[0].trimmed() + "\033[0m " + lines[endOfStyles].trimmed())
lines[endOfStyles].trimmed()) .toUtf8()
.toUtf8() .constData();
.constData();
for (auto line : lines.mid(endOfStyles + 1)) { for (auto line : lines.mid(endOfStyles + 1)) {
qDebug(discordLog) << line.toUtf8().constData(); qDebug(discordLog) << line.toUtf8().constData();
} }

View File

@@ -1,22 +0,0 @@
#include "localserver.h"
bool isProgramRunning(const QString &program_name) {
QLocalSocket socket;
socket.connectToServer(program_name);
if (socket.waitForConnected()) {
return true; // program is already running
}
return false;
}
void showErrorMessage(const char *text) {
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setText(text);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setWindowIcon(QIcon(":assets/de.shorsh.discord-screenaudio.png"));
msgBox.exec();
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "mainwindow.h"
#include <QLocalServer>
#include <QLocalSocket>
#include <QMessageBox>
bool isProgramRunning(const QString &program_name);
void showErrorMessage(const char *text);

View File

@@ -1,4 +1,4 @@
#include "localserver.h" #include "dependencycheck.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "virtmic.h" #include "virtmic.h"
@@ -8,14 +8,10 @@
#include <QApplication> #include <QApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QLocalServer>
#include <QLocalSocket>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QMessageBox>
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( QApplication::setWindowIcon(
QIcon(":assets/de.shorsh.discord-screenaudio.png")); QIcon(":assets/de.shorsh.discord-screenaudio.png"));
@@ -54,21 +50,9 @@ int main(int argc, char *argv[]) {
"--remote-debugging-port=9222 " + "--remote-debugging-port=9222 " +
qgetenv("QTWEBENGINE_CHROMIUM_FLAGS")); qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"));
checkDependencies();
MainWindow w(parser.isSet(notifySendOption)); MainWindow w(parser.isSet(notifySendOption));
// Check if discord is already running
QString program_name = "discord-screenaudio";
if (isProgramRunning(program_name)) {
// if running show error message
showErrorMessage("discord-screenaudio is already running");
return 1;
}
// open server so we can check if discord is running
QLocalServer server;
server.listen(program_name);
QObject::connect(&server, &QLocalServer::newConnection, []() {});
w.show(); w.show();
return app.exec(); return app.exec();

View File

@@ -44,10 +44,6 @@ void UserScript::setupHelpMenu() {
QString(), "https://github.com/Curve"); QString(), "https://github.com/Curve");
aboutData.addComponent("Rohrkabel", "A C++ RAII Pipewire-API Wrapper", "1.3", aboutData.addComponent("Rohrkabel", "A C++ RAII Pipewire-API Wrapper", "1.3",
"https://github.com/Soundux/rohrkabel"); "https://github.com/Soundux/rohrkabel");
aboutData.addComponent("arRPC",
"An open implementation of Discord's local RPC "
"servers<br>Copyright (c) 2022 OpenAsar",
nullptr, "https://github.com/OpenAsar/arrpc");
m_helpMenu = new KHelpMenu(MainWindow::instance(), aboutData); m_helpMenu = new KHelpMenu(MainWindow::instance(), aboutData);
#endif #endif
} }
@@ -182,7 +178,3 @@ void UserScript::showThemeDialog() {
void UserScript::installUserStyles(QString url) { void UserScript::installUserStyles(QString url) {
emit shouldInstallUserStyles(url); emit shouldInstallUserStyles(url);
} }
void UserScript::showInformation(QString title, QString message) {
QMessageBox::information(MainWindow::instance(), title, message);
}

View File

@@ -72,7 +72,6 @@ public Q_SLOTS:
void showShortcutsDialog(); void showShortcutsDialog();
void showHelpMenu(); void showHelpMenu();
void showStreamDialog(); void showStreamDialog();
void showInformation(QString title, QString message);
void stopVirtmic(); void stopVirtmic();
void startVirtmic(QString target); void startVirtmic(QString target);
void showThemeDialog(); void showThemeDialog();

View File

@@ -8,25 +8,6 @@ namespace Virtmic {
const QStringList EXCLUDE_TARGETS{"Chromium input", "discord-screenaudio"}; const QStringList EXCLUDE_TARGETS{"Chromium input", "discord-screenaudio"};
const std::string nullstr = "";
const std::string &getTarget(const pipewire::spa::dict &props) {
if (props.count("media.class") &&
props.at("media.class") == "Stream/Output/Audio") {
if (props.count("application.name") && props.at("application.name") != "")
return props.at("application.name");
else if (props.count("application.process.binary") &&
props.at("application.process.binary") != "")
return props.at("application.process.binary");
else
return props.at("node.name");
} else
return nullstr;
}
QString qGetTarget(const pipewire::spa::dict &props) {
return QString::fromStdString(getTarget(props));
}
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);
@@ -41,7 +22,14 @@ 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();
QString name = qGetTarget(info.props); QString name;
if (info.props.count("application.name") &&
info.props["application.name"] != "")
name = QString::fromStdString(info.props["application.name"]);
else
name = QString::fromStdString(
info.props["application.process.binary"]);
if (name != "" && !EXCLUDE_TARGETS.contains(name) && if (name != "" && !EXCLUDE_TARGETS.contains(name) &&
!targets.contains(name)) { !targets.contains(name)) {
targets.append(name); targets.append(name);
@@ -85,7 +73,13 @@ void start(QString _target) {
continue; continue;
auto &parent = nodes.at(parent_id); auto &parent = nodes.at(parent_id);
std::string name = getTarget(parent.props); std::string name;
if (parent.props.count("application.name") &&
parent.props["application.name"] != "")
name = parent.props["application.name"];
else
name = parent.props["application.process.binary"];
if (name == target || if (name == target ||
(target == "[All Desktop Audio]" && (target == "[All Desktop Audio]" &&
!EXCLUDE_TARGETS.contains(QString::fromStdString(name)))) { !EXCLUDE_TARGETS.contains(QString::fromStdString(name)))) {
@@ -105,7 +99,7 @@ void start(QString _target) {
} }
}; };
std::string target = _target.toUtf8().toStdString(); std::string target = _target.toLatin1().toStdString();
auto virtual_mic = core.create("adapter", auto virtual_mic = core.create("adapter",
{{"node.name", "discord-screenaudio-virtmic"}, {{"node.name", "discord-screenaudio-virtmic"},
@@ -129,8 +123,13 @@ void start(QString _target) {
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();
std::string name = getTarget(info.props); std::string name;
if (name == nullstr) if (info.props.count("application.name") &&
info.props["application.name"] != "")
name = info.props["application.name"];
else if (info.props.count("application.process.binary")) {
name = info.props["application.process.binary"];
} else
return; return;
qDebug(virtmicLog) << QString("Added: %1") qDebug(virtmicLog) << QString("Added: %1")
.arg(QString::fromStdString(name)) .arg(QString::fromStdString(name))
@@ -169,9 +168,12 @@ 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::string name = getTarget(info.props); std::string name;
if (name == nullstr) if (info.props.count("application.name") &&
return; info.props["application.name"] != "")
name = info.props["application.name"];
else
name = info.props["application.process.binary"];
qDebug(virtmicLog) << QString("Removed: %1") qDebug(virtmicLog) << QString("Removed: %1")
.arg(QString::fromStdString(name)) .arg(QString::fromStdString(name))
.toUtf8() .toUtf8()