Implement Stream Dialog
This commit is contained in:
parent
81317fd43d
commit
67087e8251
10 changed files with 394 additions and 140 deletions
|
@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||||
# set(CMAKE_AUTOUIC ON)
|
# set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
find_package(Qt5 CONFIG REQUIRED COMPONENTS
|
find_package(Qt5 CONFIG REQUIRED COMPONENTS
|
||||||
|
@ -16,6 +17,8 @@ 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/streamdialog.cpp
|
||||||
resources.qrc
|
resources.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,4 @@
|
||||||
// ==UserScript==
|
// From v0.4
|
||||||
// @name Screenshare with Audio
|
|
||||||
// @namespace https://github.com/edisionnano
|
|
||||||
// @version 0.4
|
|
||||||
// @description Screenshare with Audio on Discord
|
|
||||||
// @author Guest271314 and Samantas5855
|
|
||||||
// @match https://*.discord.com/*
|
|
||||||
// @icon https://www.google.com/s2/favicons?domain=discord.com
|
|
||||||
// @grant none
|
|
||||||
// @license MIT
|
|
||||||
// ==/UserScript==
|
|
||||||
|
|
||||||
/* jshint esversion: 8 */
|
|
||||||
|
|
||||||
navigator.mediaDevices.chromiumGetDisplayMedia =
|
navigator.mediaDevices.chromiumGetDisplayMedia =
|
||||||
navigator.mediaDevices.getDisplayMedia;
|
navigator.mediaDevices.getDisplayMedia;
|
||||||
|
@ -24,39 +12,115 @@ const getAudioDevice = async (nameOfAudioDevice) => {
|
||||||
return audioDevice;
|
return audioDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDisplayMedia = async (...args) => {
|
function setGetDisplayMedia(overrideArgs = undefined) {
|
||||||
var id;
|
const getDisplayMedia = async (...args) => {
|
||||||
try {
|
var id;
|
||||||
let myDiscordAudioSink = await getAudioDevice(
|
try {
|
||||||
"discord-screenaudio-virtmic"
|
let myDiscordAudioSink = await getAudioDevice(
|
||||||
);
|
"discord-screenaudio-virtmic"
|
||||||
id = myDiscordAudioSink.deviceId;
|
);
|
||||||
} catch (error) {
|
id = myDiscordAudioSink.deviceId;
|
||||||
id = "default";
|
} catch (error) {
|
||||||
}
|
id = "default";
|
||||||
let captureSystemAudioStream = await navigator.mediaDevices.getUserMedia({
|
}
|
||||||
audio: {
|
let captureSystemAudioStream = await navigator.mediaDevices.getUserMedia({
|
||||||
// We add our audio constraints here, to get a list of supported constraints use navigator.mediaDevices.getSupportedConstraints();
|
audio: {
|
||||||
// We must capture a microphone, we use default since its the only deviceId that is the same for every Chromium user
|
// We add our audio constraints here, to get a list of supported constraints use navigator.mediaDevices.getSupportedConstraints();
|
||||||
deviceId: {
|
// We must capture a microphone, we use default since its the only deviceId that is the same for every Chromium user
|
||||||
exact: id,
|
deviceId: {
|
||||||
|
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,
|
let [track] = captureSystemAudioStream.getAudioTracks();
|
||||||
echoCancellation: false,
|
const gdm = await navigator.mediaDevices.chromiumGetDisplayMedia(
|
||||||
noiseSuppression: false,
|
...(overrideArgs
|
||||||
// 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
|
? [overrideArgs]
|
||||||
channelCount: 2,
|
: args || [{ video: true, audio: true }])
|
||||||
// You can set more audio constraints here, bellow are some examples
|
);
|
||||||
//latency: 0,
|
gdm.addTrack(track);
|
||||||
//sampleRate: 48000,
|
return gdm;
|
||||||
//sampleSize: 16,
|
};
|
||||||
//volume: 1.0
|
navigator.mediaDevices.getDisplayMedia = getDisplayMedia;
|
||||||
},
|
}
|
||||||
});
|
|
||||||
let [track] = captureSystemAudioStream.getAudioTracks();
|
setGetDisplayMedia();
|
||||||
const gdm = await navigator.mediaDevices.chromiumGetDisplayMedia(...args);
|
|
||||||
gdm.addTrack(track);
|
const clonedElements = [];
|
||||||
return gdm;
|
const hiddenElements = [];
|
||||||
};
|
let wasStreamActive = false;
|
||||||
navigator.mediaDevices.getDisplayMedia = getDisplayMedia;
|
|
||||||
|
setInterval(() => {
|
||||||
|
const streamActive =
|
||||||
|
document.getElementsByClassName("panel-2ZFCRb activityPanel-9icbyU")
|
||||||
|
.length > 0;
|
||||||
|
|
||||||
|
if (!streamActive && wasStreamActive)
|
||||||
|
console.log("!discord-screenaudio-stream-stopped");
|
||||||
|
wasStreamActive = streamActive;
|
||||||
|
|
||||||
|
if (streamActive) {
|
||||||
|
clonedElements.forEach((el) => {
|
||||||
|
el.remove();
|
||||||
|
});
|
||||||
|
clonedElements.length = 0;
|
||||||
|
|
||||||
|
hiddenElements.forEach((el) => {
|
||||||
|
el.style.display = "block";
|
||||||
|
});
|
||||||
|
hiddenElements.length = 0;
|
||||||
|
} else {
|
||||||
|
for (const el of document.querySelectorAll(
|
||||||
|
'[aria-label="Share Your Screen"]'
|
||||||
|
)) {
|
||||||
|
elClone = el.cloneNode(true);
|
||||||
|
elClone.ariaLabel = "Share Your Screen with Audio";
|
||||||
|
elClone.title = "Share Your Screen with Audio";
|
||||||
|
elClone.addEventListener("click", () => {
|
||||||
|
console.log("!discord-screenaudio-start-stream");
|
||||||
|
});
|
||||||
|
|
||||||
|
const initialDisplay = el.style.display;
|
||||||
|
|
||||||
|
window.discordScreenaudioStartStream = (width, height, frameRate) => {
|
||||||
|
setGetDisplayMedia({
|
||||||
|
audio: true,
|
||||||
|
video: { width, height, frameRate },
|
||||||
|
});
|
||||||
|
el.click();
|
||||||
|
el.style.display = initialDisplay;
|
||||||
|
elClone.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
el.style.display = "none";
|
||||||
|
el.parentNode.insertBefore(elClone, el);
|
||||||
|
|
||||||
|
clonedElements.push(elClone);
|
||||||
|
hiddenElements.push(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
document.getElementsByClassName("dirscordScreenaudioAboutText").length == 0
|
||||||
|
) {
|
||||||
|
for (const el of document.getElementsByClassName("info-3pQQBb")) {
|
||||||
|
const aboutEl = document.createElement("div");
|
||||||
|
aboutEl.innerText = "discord-screenaudio v1.0.0-alpha";
|
||||||
|
aboutEl.style.fontSize = "12px";
|
||||||
|
aboutEl.style.color = "var(--text-muted)";
|
||||||
|
aboutEl.classList.add("dirscordScreenaudioAboutText");
|
||||||
|
el.appendChild(aboutEl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
119
src/discordpage.cpp
Normal file
119
src/discordpage.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "discordpage.h"
|
||||||
|
#include "virtmic.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QWebChannel>
|
||||||
|
#include <QWebEngineScript>
|
||||||
|
#include <QWebEngineScriptCollection>
|
||||||
|
#include <QWebEngineSettings>
|
||||||
|
|
||||||
|
DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
|
||||||
|
setBackgroundColor(QColor("#202225"));
|
||||||
|
m_virtmicProcess.setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
|
|
||||||
|
connect(this, &QWebEnginePage::featurePermissionRequested, this,
|
||||||
|
&DiscordPage::featurePermissionRequested);
|
||||||
|
|
||||||
|
settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
|
||||||
|
settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
|
||||||
|
settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent,
|
||||||
|
true);
|
||||||
|
settings()->setAttribute(
|
||||||
|
QWebEngineSettings::AllowWindowActivationFromJavaScript, true);
|
||||||
|
settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
|
||||||
|
settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture,
|
||||||
|
false);
|
||||||
|
|
||||||
|
setUrl(QUrl("https://discord.com/app"));
|
||||||
|
|
||||||
|
injectScript(":/assets/userscript.js");
|
||||||
|
|
||||||
|
connect(&m_streamDialog, &StreamDialog::requestedStreamStart, this,
|
||||||
|
&DiscordPage::startStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordPage::injectScript(QString source) {
|
||||||
|
qDebug() << "[main ] Injecting " << source;
|
||||||
|
|
||||||
|
QFile userscript(source);
|
||||||
|
|
||||||
|
if (!userscript.open(QIODevice::ReadOnly)) {
|
||||||
|
qFatal("Failed to load %s with error: %s", source.toLatin1().constData(),
|
||||||
|
userscript.errorString().toLatin1().constData());
|
||||||
|
} else {
|
||||||
|
QByteArray userscriptJs = userscript.readAll();
|
||||||
|
|
||||||
|
QWebEngineScript script;
|
||||||
|
|
||||||
|
script.setSourceCode(userscriptJs);
|
||||||
|
script.setName("userscript.js");
|
||||||
|
script.setWorldId(QWebEngineScript::MainWorld);
|
||||||
|
script.setInjectionPoint(QWebEngineScript::DocumentCreation);
|
||||||
|
script.setRunsOnSubFrames(false);
|
||||||
|
|
||||||
|
scripts().insert(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordPage::featurePermissionRequested(const QUrl &securityOrigin,
|
||||||
|
QWebEnginePage::Feature feature) {
|
||||||
|
// Allow every permission asked
|
||||||
|
setFeaturePermission(securityOrigin, feature,
|
||||||
|
QWebEnginePage::PermissionGrantedByUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiscordPage::acceptNavigationRequest(const QUrl &url,
|
||||||
|
QWebEnginePage::NavigationType type,
|
||||||
|
bool isMainFrame) {
|
||||||
|
qDebug() << url;
|
||||||
|
if (type == QWebEnginePage::NavigationTypeLinkClicked) {
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void DiscordPage::stopVirtmic() {
|
||||||
|
if (m_virtmicProcess.state() == QProcess::Running) {
|
||||||
|
qDebug() << "[virtmic] Stopping Virtmic";
|
||||||
|
m_virtmicProcess.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordPage::startVirtmic(QString target) {
|
||||||
|
if (target != "") {
|
||||||
|
qDebug() << "[virtmic] Starting Virtmic with target" << target;
|
||||||
|
m_virtmicProcess.start(QApplication::arguments()[0], {"--virtmic", target});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordPage::javaScriptConsoleMessage(
|
||||||
|
QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message,
|
||||||
|
int lineNumber, const QString &sourceID) {
|
||||||
|
if (message == "!discord-screenaudio-start-stream") {
|
||||||
|
if (m_streamDialog.isHidden())
|
||||||
|
m_streamDialog.setHidden(false);
|
||||||
|
else
|
||||||
|
m_streamDialog.activateWindow();
|
||||||
|
} else if (message == "!discord-screenaudio-stream-stopped") {
|
||||||
|
stopVirtmic();
|
||||||
|
} else {
|
||||||
|
qDebug() << "[discord]" << message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordPage::startStream(QString target, uint width, uint height,
|
||||||
|
uint frameRate) {
|
||||||
|
stopVirtmic();
|
||||||
|
startVirtmic(target);
|
||||||
|
// Wait a bit for the virtmic to start
|
||||||
|
QTimer::singleShot(target == "" ? 0 : 200, [=]() {
|
||||||
|
runJavaScript(QString("window.discordScreenaudioStartStream(%1, %2, %3);")
|
||||||
|
.arg(width)
|
||||||
|
.arg(height)
|
||||||
|
.arg(frameRate));
|
||||||
|
});
|
||||||
|
}
|
33
src/discordpage.h
Normal file
33
src/discordpage.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "streamdialog.h"
|
||||||
|
#include "virtmic.h"
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QWebEnginePage>
|
||||||
|
|
||||||
|
class DiscordPage : public QWebEnginePage {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DiscordPage(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
StreamDialog m_streamDialog;
|
||||||
|
QProcess m_virtmicProcess;
|
||||||
|
bool acceptNavigationRequest(const QUrl &url,
|
||||||
|
QWebEnginePage::NavigationType type,
|
||||||
|
bool isMainFrame) override;
|
||||||
|
void
|
||||||
|
javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level,
|
||||||
|
const QString &message, int lineNumber,
|
||||||
|
const QString &sourceID) override;
|
||||||
|
void injectScript(QString source);
|
||||||
|
void stopVirtmic();
|
||||||
|
void startVirtmic(QString target);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void featurePermissionRequested(const QUrl &securityOrigin,
|
||||||
|
QWebEnginePage::Feature feature);
|
||||||
|
void startStream(QString target, uint width, uint height, uint frameRate);
|
||||||
|
};
|
24
src/main.cpp
24
src/main.cpp
|
@ -1,8 +1,32 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "virtmic.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
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::setApplicationVersion("1.0.0-alpha");
|
||||||
|
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.setApplicationDescription(
|
||||||
|
"Custom Discord client with the ability to stream audio on Linux");
|
||||||
|
parser.addHelpOption();
|
||||||
|
parser.addVersionOption();
|
||||||
|
QCommandLineOption virtmicOption("virtmic", "Start the Virtual Microphone",
|
||||||
|
"target");
|
||||||
|
parser.addOption(virtmicOption);
|
||||||
|
#ifdef DEBUG
|
||||||
|
parser.addOption(QCommandLineOption(
|
||||||
|
"remote-debugging-port", "Chromium Remote Debugging Port", "port"));
|
||||||
|
#endif
|
||||||
|
parser.process(app);
|
||||||
|
|
||||||
|
if (parser.isSet(virtmicOption)) {
|
||||||
|
Virtmic::start(parser.value(virtmicOption));
|
||||||
|
}
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "virtmic.h"
|
#include "virtmic.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
@ -16,96 +17,14 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
||||||
auto centralWidget = new QWidget;
|
setupWebView();
|
||||||
|
|
||||||
auto layout = new QGridLayout;
|
|
||||||
layout->setAlignment(Qt::AlignCenter);
|
|
||||||
|
|
||||||
auto label = new QLabel;
|
|
||||||
label->setText("Which app do you want to stream sound from?");
|
|
||||||
|
|
||||||
auto comboBox = new QComboBox;
|
|
||||||
for (auto target : Virtmic::getTargets()) {
|
|
||||||
comboBox->addItem(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto button = new QPushButton;
|
|
||||||
button->setText("Confirm");
|
|
||||||
connect(button, &QPushButton::clicked, [=]() {
|
|
||||||
auto target = comboBox->currentText();
|
|
||||||
auto thread = QThread::create([=]() { Virtmic::start(target); });
|
|
||||||
thread->start();
|
|
||||||
setupWebView();
|
|
||||||
});
|
|
||||||
|
|
||||||
layout->addWidget(label, 0, 0);
|
|
||||||
layout->addWidget(comboBox, 1, 0);
|
|
||||||
layout->addWidget(button, 2, 0, Qt::AlignRight);
|
|
||||||
centralWidget->setLayout(layout);
|
|
||||||
setCentralWidget(centralWidget);
|
|
||||||
resize(1000, 700);
|
resize(1000, 700);
|
||||||
showMaximized();
|
showMaximized();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setupWebView() {
|
void MainWindow::setupWebView() {
|
||||||
m_webView = new QWebEngineView(this);
|
m_webView = new QWebEngineView(this);
|
||||||
m_webView->page()->setBackgroundColor(QColor("#202225"));
|
auto page = new DiscordPage;
|
||||||
|
m_webView->setPage(page);
|
||||||
// TODO: Custom QWebEnginePage that implements acceptNavigationRequest
|
|
||||||
connect(m_webView->page(), &QWebEnginePage::featurePermissionRequested, this,
|
|
||||||
&MainWindow::featurePermissionRequested);
|
|
||||||
m_webView->settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled,
|
|
||||||
true);
|
|
||||||
m_webView->settings()->setAttribute(
|
|
||||||
QWebEngineSettings::JavascriptCanOpenWindows, true);
|
|
||||||
m_webView->settings()->setAttribute(
|
|
||||||
QWebEngineSettings::AllowRunningInsecureContent, true);
|
|
||||||
m_webView->settings()->setAttribute(
|
|
||||||
QWebEngineSettings::AllowWindowActivationFromJavaScript, true);
|
|
||||||
m_webView->settings()->setAttribute(
|
|
||||||
QWebEngineSettings::FullScreenSupportEnabled, true);
|
|
||||||
m_webView->settings()->setAttribute(
|
|
||||||
QWebEngineSettings::PlaybackRequiresUserGesture, false);
|
|
||||||
|
|
||||||
m_webView->setUrl(QUrl("https://discord.com/app"));
|
|
||||||
|
|
||||||
const char *userscriptSrc = ":/assets/userscript.js";
|
|
||||||
QFile userscript(userscriptSrc);
|
|
||||||
|
|
||||||
if (!userscript.open(QIODevice::ReadOnly)) {
|
|
||||||
qFatal("Failed to load %s with error: %s", userscriptSrc,
|
|
||||||
userscript.errorString().toLatin1().constData());
|
|
||||||
} else {
|
|
||||||
QByteArray userscriptJs = userscript.readAll();
|
|
||||||
|
|
||||||
QWebEngineScript script;
|
|
||||||
|
|
||||||
script.setSourceCode(userscriptJs);
|
|
||||||
script.setName("userscript.js");
|
|
||||||
script.setWorldId(QWebEngineScript::MainWorld);
|
|
||||||
script.setInjectionPoint(QWebEngineScript::DocumentCreation);
|
|
||||||
script.setRunsOnSubFrames(false);
|
|
||||||
|
|
||||||
m_webView->page()->scripts().insert(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
setCentralWidget(m_webView);
|
setCentralWidget(m_webView);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::featurePermissionRequested(const QUrl &securityOrigin,
|
|
||||||
QWebEnginePage::Feature feature) {
|
|
||||||
// if (feature == QWebEnginePage::MediaAudioCapture ||
|
|
||||||
// feature == QWebEnginePage::MediaVideoCapture ||
|
|
||||||
// feature == QWebEnginePage::MediaAudioVideoCapture ||
|
|
||||||
// feature == QWebEnginePage::DesktopVideoCapture ||
|
|
||||||
// feature == QWebEnginePage::DesktopAudioVideoCapture)
|
|
||||||
// m_webView->page()->setFeaturePermission(
|
|
||||||
// securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
|
|
||||||
// else
|
|
||||||
// m_webView->page()->setFeaturePermission(
|
|
||||||
// securityOrigin, feature, QWebEnginePage::PermissionDeniedByUser);
|
|
||||||
m_webView->page()->setFeaturePermission(
|
|
||||||
securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow::~MainWindow() = default;
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "discordpage.h"
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
@ -13,15 +15,10 @@ class MainWindow : public QMainWindow {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(QWidget *parent = nullptr);
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupWebView();
|
void setupWebView();
|
||||||
QWebEngineView *m_webView;
|
QWebEngineView *m_webView;
|
||||||
QWebEngineProfile *prepareProfile();
|
QWebEngineProfile *prepareProfile();
|
||||||
QThread *m_virtmicThread;
|
DiscordPage *m_discordPage;
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void featurePermissionRequested(const QUrl &securityOrigin,
|
|
||||||
QWebEnginePage::Feature feature);
|
|
||||||
};
|
};
|
||||||
|
|
71
src/streamdialog.cpp
Normal file
71
src/streamdialog.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "streamdialog.h"
|
||||||
|
#include "virtmic.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSizePolicy>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
StreamDialog::StreamDialog() : QWidget() {
|
||||||
|
auto layout = new QVBoxLayout;
|
||||||
|
|
||||||
|
auto targetLabel = new QLabel;
|
||||||
|
targetLabel->setText("Which app do you want to stream sound from?");
|
||||||
|
layout->addWidget(targetLabel);
|
||||||
|
|
||||||
|
m_targetComboBox = new QComboBox;
|
||||||
|
m_targetComboBox->addItem("None");
|
||||||
|
for (auto target : Virtmic::getTargets()) {
|
||||||
|
m_targetComboBox->addItem(target);
|
||||||
|
}
|
||||||
|
layout->addWidget(m_targetComboBox);
|
||||||
|
|
||||||
|
auto qualityLabel = new QLabel;
|
||||||
|
qualityLabel->setText("Stream Quality");
|
||||||
|
layout->addWidget(qualityLabel);
|
||||||
|
|
||||||
|
auto qualityHBox = new QHBoxLayout;
|
||||||
|
layout->addLayout(qualityHBox);
|
||||||
|
|
||||||
|
m_qualityResolutionComboBox = new QComboBox;
|
||||||
|
m_qualityResolutionComboBox->addItem("2160p", "3840x2160");
|
||||||
|
m_qualityResolutionComboBox->addItem("1440p", "2560x1440");
|
||||||
|
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;
|
||||||
|
m_qualityFPSComboBox->addItem("144 FPS", 144);
|
||||||
|
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 button = new QPushButton;
|
||||||
|
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");
|
||||||
|
setFixedSize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamDialog::startStream() {
|
||||||
|
auto resolution =
|
||||||
|
m_qualityResolutionComboBox->currentData().toString().split('x');
|
||||||
|
emit requestedStreamStart(m_targetComboBox->currentText(),
|
||||||
|
resolution[0].toUInt(), resolution[1].toUInt(),
|
||||||
|
m_qualityFPSComboBox->currentData().toUInt());
|
||||||
|
setHidden(true);
|
||||||
|
}
|
24
src/streamdialog.h
Normal file
24
src/streamdialog.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class StreamDialog : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit StreamDialog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *m_targetComboBox;
|
||||||
|
QComboBox *m_qualityResolutionComboBox;
|
||||||
|
QComboBox *m_qualityFPSComboBox;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void requestedStreamStart(QString target, uint width, uint height,
|
||||||
|
uint frameRate);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void startStream();
|
||||||
|
};
|
|
@ -10,4 +10,4 @@ namespace Virtmic {
|
||||||
QVector<QString> getTargets();
|
QVector<QString> getTargets();
|
||||||
void start(QString _target);
|
void start(QString _target);
|
||||||
|
|
||||||
} // namespace Virtmic
|
} // namespace Virtmic
|
||||||
|
|
Loading…
Reference in a new issue