Compare commits
	
		
			16 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | bfb0714b13 | ||
|  | 374b854261 | ||
|  | 1f6105f76b | ||
|  | 3071159332 | ||
|  | f2de080e1b | ||
|  | f4a60f281d | ||
|  | d693535d53 | ||
|  | e41af697f7 | ||
|  | b0a8815bb8 | ||
|  | 150fd4364e | ||
|  | a0a2924796 | ||
|  | 3c48621427 | ||
|  | 9faabe1f3e | ||
|  | 68473d04d8 | ||
|  | 7c8f72b8d8 | ||
|  | 27cdd9f9a5 | 
| @@ -13,24 +13,27 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") | ||||
| string(TIMESTAMP TIMESTAMP %s) | ||||
| # set(CMAKE_AUTOUIC ON) | ||||
|  | ||||
| find_package(Qt5 CONFIG REQUIRED COMPONENTS  | ||||
|   Widgets | ||||
|   WebEngineWidgets | ||||
| ) | ||||
| find_package(Qt5 COMPONENTS Widgets) | ||||
| if (Qt5_FOUND) | ||||
|   find_package(Qt5 CONFIG REQUIRED COMPONENTS Widgets WebEngineWidgets) | ||||
|  | ||||
| find_package(KF5Notifications) | ||||
| if(KF5Notifications_FOUND) | ||||
|   add_definitions( -DKNOTIFICATIONS ) | ||||
| endif() | ||||
|   find_package(KF5Notifications) | ||||
|   if(KF5Notifications_FOUND) | ||||
|     add_definitions( -DKNOTIFICATIONS ) | ||||
|   endif() | ||||
|  | ||||
| find_package(KF5XmlGui) | ||||
| if(KF5XmlGui_FOUND) | ||||
|   add_definitions( -DKXMLGUI ) | ||||
| endif() | ||||
|   find_package(KF5XmlGui) | ||||
|   if(KF5XmlGui_FOUND) | ||||
|     add_definitions( -DKXMLGUI ) | ||||
|   endif() | ||||
|  | ||||
| find_package(KF5GlobalAccel) | ||||
| if(KF5GlobalAccel_FOUND) | ||||
|   add_definitions( -DKGLOBALACCEL ) | ||||
|   find_package(KF5GlobalAccel) | ||||
|   if(KF5GlobalAccel_FOUND) | ||||
|     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() | ||||
|  | ||||
| set(discord-screenaudio_SRC | ||||
| @@ -66,7 +69,7 @@ add_subdirectory(submodules/rohrkabel) | ||||
|  | ||||
| add_executable(discord-screenaudio ${discord-screenaudio_SRC}) | ||||
|  | ||||
| target_link_libraries(discord-screenaudio Qt5::Widgets Qt5::WebEngineWidgets rohrkabel) | ||||
| target_link_libraries(discord-screenaudio Qt::Widgets Qt::WebEngineWidgets rohrkabel) | ||||
|  | ||||
| if(KF5Notifications_FOUND) | ||||
|   target_link_libraries(discord-screenaudio KF5::Notifications) | ||||
|   | ||||
| @@ -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 | ||||
| ([see explanation](#how-it-works)). | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 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 | ||||
| @@ -50,6 +50,8 @@ You have multiple options: | ||||
| ### Requirements | ||||
|  | ||||
| - Basic building tools | ||||
| - An up-to-date system (I can't guarantee that it works on Debian or Ubuntu | ||||
|   20/21) | ||||
| - CMake | ||||
| - Qt5 and QtWebEngine | ||||
| - **PipeWire** (it currently doesn't work with PulseAudio) | ||||
| @@ -57,7 +59,7 @@ You have multiple options: | ||||
| - _Kf5Notifications (optional, for better notifications)_ | ||||
| - _KXMLGui and KGlobalAccel (optional, for keybinds)_ | ||||
|  | ||||
| On Debian: | ||||
| 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` | ||||
|  | ||||
| ### Building | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|   <metadata_license>CC0-1.0</metadata_license> | ||||
|   <project_license>GPL-3.0+</project_license> | ||||
|   <name>discord-screenaudio</name> | ||||
|   <developer_name>Malte Jürgens</developer_name> | ||||
|   <releases> | ||||
|     <release version="${DISCORD_SCEENAUDIO_VERSION_FULL}" timestamp="${TIMESTAMP}" /> | ||||
|   </releases> | ||||
|   | ||||
| @@ -25,7 +25,7 @@ const getAudioDevice = async (nameOfAudioDevice) => { | ||||
|   return audioDevice; | ||||
| }; | ||||
|  | ||||
| function setGetDisplayMedia(overrideArgs = undefined) { | ||||
| function setGetDisplayMedia(video = true, overrideArgs = undefined) { | ||||
|   const getDisplayMedia = async (...args) => { | ||||
|     var id; | ||||
|     try { | ||||
| @@ -63,6 +63,7 @@ function setGetDisplayMedia(overrideArgs = undefined) { | ||||
|         : args || [{ video: true, audio: true }]) | ||||
|     ); | ||||
|     gdm.addTrack(track); | ||||
|     if (!video) for (const track of gdm.getVideoTracks()) track.enabled = false; | ||||
|     return gdm; | ||||
|   }; | ||||
|   navigator.mediaDevices.getDisplayMedia = getDisplayMedia; | ||||
| @@ -111,9 +112,16 @@ setInterval(() => { | ||||
|  | ||||
|       const initialDisplay = el.style.display; | ||||
|  | ||||
|       window.discordScreenaudioStartStream = (width, height, frameRate) => { | ||||
|         window.discordScreenaudioResolutionString = `${height}p ${frameRate}FPS`; | ||||
|         setGetDisplayMedia({ | ||||
|       window.discordScreenaudioStartStream = ( | ||||
|         video, | ||||
|         width, | ||||
|         height, | ||||
|         frameRate | ||||
|       ) => { | ||||
|         window.discordScreenaudioResolutionString = video | ||||
|           ? `${height}p ${frameRate}FPS` | ||||
|           : "Audio Only"; | ||||
|         setGetDisplayMedia(video, { | ||||
|           audio: true, | ||||
|           video: { width, height, frameRate }, | ||||
|         }); | ||||
| @@ -163,7 +171,7 @@ setInterval(() => { | ||||
|     document | ||||
|       .getElementById("keybinds-tab") | ||||
|       ?.getElementsByClassName( | ||||
|         "container-3jbRo5 info-1hMolH fontSize16-3zr6Io browserNotice-1u-Y5o" | ||||
|         "container-3jbRo5 info-1hMolH browserNotice-1u-Y5o" | ||||
|       ).length | ||||
|   ) { | ||||
|     const el = document | ||||
| @@ -183,14 +191,28 @@ setInterval(() => { | ||||
|     el.appendChild(div); | ||||
|   } | ||||
|  | ||||
|   const muteBtn = document.getElementsByClassName( | ||||
|     "button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F" | ||||
|   )[0]; | ||||
|   window.discordScreenaudioToggleMute = () => muteBtn.click(); | ||||
|   const deafenBtn = document.getElementsByClassName( | ||||
|     "button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F" | ||||
|   )[1]; | ||||
|   window.discordScreenaudioToggleDeafen = () => deafenBtn.click(); | ||||
|   const buttonContainer = | ||||
|     document.getElementsByClassName("container-YkUktl")[0]; | ||||
|   if (!buttonContainer) { | ||||
|     console.log( | ||||
|       "dsa: Cannot locate Mute/Deafen/Settings button container, please report this on GitHub" | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   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) { | ||||
|     for (const el of document.getElementsByClassName( | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
| #include <QDesktopServices> | ||||
| #include <QFile> | ||||
| #include <QMessageBox> | ||||
| #include <QNetworkReply> | ||||
| #include <QTimer> | ||||
| #include <QWebChannel> | ||||
| #include <QWebEngineScript> | ||||
| @@ -128,14 +129,13 @@ void DiscordPage::injectScriptText(QString name, QString content) { | ||||
| } | ||||
|  | ||||
| void DiscordPage::injectScriptFile(QString name, QString source) { | ||||
|   QFile userscript(source); | ||||
|   QFile file(source); | ||||
|  | ||||
|   if (!userscript.open(QIODevice::ReadOnly)) { | ||||
|   if (!file.open(QIODevice::ReadOnly)) { | ||||
|     qFatal("Failed to load %s with error: %s", source.toLatin1().constData(), | ||||
|            userscript.errorString().toLatin1().constData()); | ||||
|            file.errorString().toLatin1().constData()); | ||||
|   } else { | ||||
|     QByteArray userscriptJs = userscript.readAll(); | ||||
|     injectScriptText(name, userscriptJs); | ||||
|     injectScriptText(name, file.readAll()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -186,10 +186,8 @@ void DiscordPage::stopVirtmic() { | ||||
| } | ||||
|  | ||||
| void DiscordPage::startVirtmic(QString target) { | ||||
|   if (target != "None") { | ||||
|     qDebug(virtmicLog) << "Starting Virtmic with target" << target; | ||||
|     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( | ||||
| @@ -230,16 +228,18 @@ void DiscordPage::javaScriptConsoleMessage( | ||||
|   } | ||||
| } | ||||
|  | ||||
| void DiscordPage::startStream(QString target, uint width, uint height, | ||||
|                               uint frameRate) { | ||||
| void DiscordPage::startStream(bool video, bool audio, uint width, uint height, | ||||
|                               uint frameRate, QString target) { | ||||
|   stopVirtmic(); | ||||
|   startVirtmic(target); | ||||
|   startVirtmic(audio ? target : "[None]"); | ||||
|   // Wait a bit for the virtmic to start | ||||
|   QTimer::singleShot(target == "None" ? 0 : 200, [=]() { | ||||
|     runJavaScript(QString("window.discordScreenaudioStartStream(%1, %2, %3);") | ||||
|                       .arg(width) | ||||
|                       .arg(height) | ||||
|                       .arg(frameRate)); | ||||
|   QTimer::singleShot(200, [=]() { | ||||
|     runJavaScript( | ||||
|         QString("window.discordScreenaudioStartStream(%1, %2, %3, %4);") | ||||
|             .arg(video) | ||||
|             .arg(video ? width : 32) | ||||
|             .arg(video ? height : 16) | ||||
|             .arg(video ? frameRate : 1)); | ||||
|   }); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -37,8 +37,8 @@ private: | ||||
|   javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level, | ||||
|                            const QString &message, int lineNumber, | ||||
|                            const QString &sourceID) override; | ||||
|   void injectScriptText(QString name, QString source); | ||||
|   void injectScriptFile(QString name, QString content); | ||||
|   void injectScriptText(QString name, QString content); | ||||
|   void injectScriptFile(QString name, QString source); | ||||
|   void stopVirtmic(); | ||||
|   void startVirtmic(QString target); | ||||
|   void toggleMute(); | ||||
| @@ -47,7 +47,8 @@ private: | ||||
| private Q_SLOTS: | ||||
|   void featurePermissionRequested(const QUrl &securityOrigin, | ||||
|                                   QWebEnginePage::Feature feature); | ||||
|   void startStream(QString target, uint width, uint height, uint frameRate); | ||||
|   void startStream(bool video, bool audio, uint width, uint height, | ||||
|                    uint frameRate, QString target); | ||||
| }; | ||||
|  | ||||
| // Will immediately get destroyed again but is needed for navigation to | ||||
|   | ||||
| @@ -30,6 +30,9 @@ int main(int argc, char *argv[]) { | ||||
|   QCommandLineOption degubOption("remote-debugging", | ||||
|                                  "Open Chromium Remote Debugging on port 9222"); | ||||
|   parser.addOption(degubOption); | ||||
|   QCommandLineOption notifySendOption( | ||||
|       "notify-send", "Use notify-send instead of QT/KF5 notifications"); | ||||
|   parser.addOption(notifySendOption); | ||||
|  | ||||
|   parser.process(app); | ||||
|  | ||||
| @@ -46,7 +49,7 @@ int main(int argc, char *argv[]) { | ||||
|             "--remote-debugging-port=9222 " + | ||||
|                 qgetenv("QTWEBENGINE_CHROMIUM_FLAGS")); | ||||
|  | ||||
|   MainWindow w; | ||||
|   MainWindow w(parser.isSet(notifySendOption)); | ||||
|   w.show(); | ||||
|  | ||||
|   return app.exec(); | ||||
|   | ||||
| @@ -24,9 +24,11 @@ | ||||
|  | ||||
| MainWindow *MainWindow::m_instance = nullptr; | ||||
|  | ||||
| MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { | ||||
| MainWindow::MainWindow(bool useNotifySend, QWidget *parent) | ||||
|     : QMainWindow(parent) { | ||||
|   assert(MainWindow::m_instance == nullptr); | ||||
|   MainWindow::m_instance = this; | ||||
|   m_useNotifySend = useNotifySend; | ||||
|   setupWebView(); | ||||
|   resize(1000, 700); | ||||
|   showMaximized(); | ||||
| @@ -40,22 +42,36 @@ void MainWindow::setupWebView() { | ||||
|   m_webView = new QWebEngineView(this); | ||||
|   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 | ||||
|   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(); | ||||
|       }); | ||||
|             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); | ||||
| } | ||||
|   | ||||
| @@ -14,7 +14,7 @@ class MainWindow : public QMainWindow { | ||||
|   Q_OBJECT | ||||
|  | ||||
| public: | ||||
|   explicit MainWindow(QWidget *parent = nullptr); | ||||
|   explicit MainWindow(bool useNotifySend = false, QWidget *parent = nullptr); | ||||
|   static MainWindow *instance(); | ||||
|  | ||||
| private: | ||||
| @@ -25,6 +25,12 @@ private: | ||||
|   void closeEvent(QCloseEvent *event) override; | ||||
|   bool m_wasMaximized; | ||||
|   static MainWindow *m_instance; | ||||
|   bool m_useNotifySend; | ||||
| #ifdef KNOTIFICATIONS | ||||
|   bool m_useKF5Notifications = true; | ||||
| #else | ||||
|   bool m_useKF5Notifications = false; | ||||
| #endif | ||||
|  | ||||
| private Q_SLOTS: | ||||
|   void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); | ||||
|   | ||||
| @@ -12,70 +12,96 @@ | ||||
| StreamDialog::StreamDialog() : QWidget() { | ||||
|   setAttribute(Qt::WA_QuitOnClose, false); | ||||
|  | ||||
|   auto layout = new QVBoxLayout(this); | ||||
|   layout->setSizeConstraint(QLayout::SetFixedSize); | ||||
|   { | ||||
|     auto layout = new QVBoxLayout(this); | ||||
|     layout->setSizeConstraint(QLayout::SetFixedSize); | ||||
|  | ||||
|   auto targetLabel = new QLabel(this); | ||||
|   targetLabel->setText("Which app do you want to stream sound from?"); | ||||
|   layout->addWidget(targetLabel); | ||||
|     m_videoGroupBox = new QGroupBox(this); | ||||
|     m_videoGroupBox->setTitle("Video"); | ||||
|     m_videoGroupBox->setCheckable(true); | ||||
|     layout->addWidget(m_videoGroupBox); | ||||
|  | ||||
|   auto targetHBox = new QHBoxLayout(this); | ||||
|   layout->addLayout(targetHBox); | ||||
|     { | ||||
|       auto videoLayout = new QVBoxLayout(this); | ||||
|       m_videoGroupBox->setLayout(videoLayout); | ||||
|  | ||||
|   m_targetComboBox = new QComboBox(this); | ||||
|   updateTargets(); | ||||
|   targetHBox->addWidget(m_targetComboBox); | ||||
|       auto resolutionLabel = new QLabel(this); | ||||
|       resolutionLabel->setText("Resolution"); | ||||
|       videoLayout->addWidget(resolutionLabel); | ||||
|  | ||||
|   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); | ||||
|       m_resolutionComboBox = new QComboBox(this); | ||||
|       m_resolutionComboBox->addItem("2160p", "3840x2160"); | ||||
|       m_resolutionComboBox->addItem("1440p", "2560x1440"); | ||||
|       m_resolutionComboBox->addItem("1080p", "1920x1080"); | ||||
|       m_resolutionComboBox->addItem("720p", "1280x720"); | ||||
|       m_resolutionComboBox->addItem("480p", "854x480"); | ||||
|       m_resolutionComboBox->addItem("360p", "640x360"); | ||||
|       m_resolutionComboBox->addItem("240p", "426x240"); | ||||
|       m_resolutionComboBox->setCurrentText("720p"); | ||||
|       videoLayout->addWidget(m_resolutionComboBox); | ||||
|  | ||||
|   auto qualityLabel = new QLabel(this); | ||||
|   qualityLabel->setText("Stream Quality"); | ||||
|   layout->addWidget(qualityLabel); | ||||
|       auto framerateLabel = new QLabel(this); | ||||
|       framerateLabel->setText("Framerate"); | ||||
|       videoLayout->addWidget(framerateLabel); | ||||
|  | ||||
|   auto qualityHBox = new QHBoxLayout(this); | ||||
|   layout->addLayout(qualityHBox); | ||||
|       m_framerateComboBox = new QComboBox(this); | ||||
|       m_framerateComboBox->addItem("144 FPS", 144); | ||||
|       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_qualityResolutionComboBox = new QComboBox(this); | ||||
|   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_audioGroupBox = new QGroupBox(this); | ||||
|     m_audioGroupBox->setCheckable(true); | ||||
|     m_audioGroupBox->setTitle("Audio"); | ||||
|     layout->addWidget(m_audioGroupBox); | ||||
|  | ||||
|   m_qualityFPSComboBox = new QComboBox(this); | ||||
|   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 audioLayout = new QVBoxLayout(this); | ||||
|       m_audioGroupBox->setLayout(audioLayout); | ||||
|  | ||||
|   auto button = new QPushButton(this); | ||||
|   button->setText("Start Stream"); | ||||
|   connect(button, &QPushButton::clicked, this, &StreamDialog::startStream); | ||||
|   layout->addWidget(button, Qt::AlignRight | Qt::AlignBottom); | ||||
|       auto targetLabel = new QLabel(this); | ||||
|       targetLabel->setText("Audio Source"); | ||||
|       audioLayout->addWidget(targetLabel); | ||||
|  | ||||
|   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"); | ||||
| } | ||||
|  | ||||
| void StreamDialog::startStream() { | ||||
|   auto resolution = | ||||
|       m_qualityResolutionComboBox->currentData().toString().split('x'); | ||||
|   emit requestedStreamStart(m_targetComboBox->currentText(), | ||||
|   auto resolution = m_resolutionComboBox->currentData().toString().split('x'); | ||||
|   emit requestedStreamStart(m_videoGroupBox->isChecked(), | ||||
|                             m_audioGroupBox->isChecked(), | ||||
|                             resolution[0].toUInt(), resolution[1].toUInt(), | ||||
|                             m_qualityFPSComboBox->currentData().toUInt()); | ||||
|                             m_framerateComboBox->currentData().toUInt(), | ||||
|                             m_targetComboBox->currentText()); | ||||
|   setHidden(true); | ||||
| } | ||||
|  | ||||
| @@ -83,7 +109,6 @@ void StreamDialog::updateTargets() { | ||||
|   auto lastTarget = m_targetComboBox->currentText(); | ||||
|  | ||||
|   m_targetComboBox->clear(); | ||||
|   m_targetComboBox->addItem("[None]"); | ||||
|   m_targetComboBox->addItem("[All Desktop Audio]"); | ||||
|   for (auto target : Virtmic::getTargets()) { | ||||
|     m_targetComboBox->addItem(target); | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| #include <QComboBox> | ||||
| #include <QDialog> | ||||
| #include <QGroupBox> | ||||
| #include <QWidget> | ||||
|  | ||||
| class StreamDialog : public QWidget { | ||||
| @@ -12,12 +13,14 @@ public: | ||||
|  | ||||
| private: | ||||
|   QComboBox *m_targetComboBox; | ||||
|   QComboBox *m_qualityResolutionComboBox; | ||||
|   QComboBox *m_qualityFPSComboBox; | ||||
|   QComboBox *m_resolutionComboBox; | ||||
|   QComboBox *m_framerateComboBox; | ||||
|   QGroupBox *m_videoGroupBox; | ||||
|   QGroupBox *m_audioGroupBox; | ||||
|  | ||||
| Q_SIGNALS: | ||||
|   void requestedStreamStart(QString target, uint width, uint height, | ||||
|                             uint frameRate); | ||||
|   void requestedStreamStart(bool video, bool audio, uint width, uint height, | ||||
|                             uint frameRate, QString target); | ||||
|  | ||||
| public Q_SLOTS: | ||||
|   void updateTargets(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user