mirror of
https://github.com/theCheeseboard/thedesk.git
synced 2025-01-22 18:32:09 -05:00
Allow moving audio streams between devices
This commit is contained in:
parent
bd60242dec
commit
169270e195
15 changed files with 282 additions and 5 deletions
|
@ -37,6 +37,7 @@ Common::DevicePort Common::portForSink(PulseAudioQt::Sink* sink) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (port != nullptr) {
|
||||
QString newPort;
|
||||
if (port->name().contains("headphones", Qt::CaseInsensitive)) {
|
||||
|
|
|
@ -54,6 +54,8 @@ void MicChunk::updateSourceOutputs() {
|
|||
// }
|
||||
}
|
||||
|
||||
micClients.removeDuplicates();
|
||||
|
||||
if (micClients.isEmpty()) {
|
||||
if (StateManager::barManager()->isChunkRegistered(this)) StateManager::barManager()->removeChunk(this);
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "quickwidgetsink.h"
|
||||
#include "ui_quickwidgetsink.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <the-libs_global.h>
|
||||
#include <Context>
|
||||
#include <Server>
|
||||
|
@ -27,6 +28,8 @@
|
|||
struct QuickWidgetSinkPrivate {
|
||||
PulseAudioQt::Sink* sink;
|
||||
bool changingVolume = false;
|
||||
|
||||
QMenu* menu;
|
||||
};
|
||||
|
||||
QuickWidgetSink::QuickWidgetSink(PulseAudioQt::Sink* sink, QWidget* parent) :
|
||||
|
@ -36,12 +39,13 @@ QuickWidgetSink::QuickWidgetSink(PulseAudioQt::Sink* sink, QWidget* parent) :
|
|||
d = new QuickWidgetSinkPrivate();
|
||||
d->sink = sink;
|
||||
|
||||
ui->nameLabel->setText(this->fontMetrics().elidedText(sink->description(), Qt::ElideRight, SC_DPI(200)));
|
||||
|
||||
connect(PulseAudioQt::Context::instance()->server(), &PulseAudioQt::Server::defaultSinkChanged, this, &QuickWidgetSink::updateVisibility);
|
||||
connect(PulseAudioQt::Context::instance()->server(), &PulseAudioQt::Server::defaultSinkChanged, this, &QuickWidgetSink::updateDefault);
|
||||
updateDefault();
|
||||
|
||||
connect(sink, &PulseAudioQt::Sink::volumeChanged, this, &QuickWidgetSink::updateVolume);
|
||||
connect(sink, &PulseAudioQt::Sink::propertiesChanged, this, &QuickWidgetSink::updateName);
|
||||
updateVolume();
|
||||
updateName();
|
||||
|
||||
connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkInputAdded, this, &QuickWidgetSink::sinkInputAdded);
|
||||
connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkInputRemoved, this, &QuickWidgetSink::updateVisibility);
|
||||
|
@ -50,6 +54,11 @@ QuickWidgetSink::QuickWidgetSink(PulseAudioQt::Sink* sink, QWidget* parent) :
|
|||
|
||||
this->setFixedWidth(SC_DPI(600));
|
||||
ui->nameLabel->setFixedWidth(SC_DPI(200));
|
||||
|
||||
d->menu = new QMenu();
|
||||
d->menu->addAction(ui->actionMake_Default);
|
||||
d->menu->addAction(ui->actionMove_All_Applications);
|
||||
ui->menuButton->setMenu(d->menu);
|
||||
}
|
||||
|
||||
QuickWidgetSink::~QuickWidgetSink() {
|
||||
|
@ -64,6 +73,11 @@ void QuickWidgetSink::updateVolume() {
|
|||
ui->volumeSlider->setValue(volume);
|
||||
}
|
||||
|
||||
void QuickWidgetSink::updateDefault() {
|
||||
ui->actionMake_Default->setVisible(PulseAudioQt::Context::instance()->server()->defaultSink() != d->sink);
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
void QuickWidgetSink::on_volumeSlider_sliderPressed() {
|
||||
d->changingVolume = true;
|
||||
}
|
||||
|
@ -93,8 +107,23 @@ void QuickWidgetSink::updateVisibility() {
|
|||
this->setVisible(false);
|
||||
}
|
||||
|
||||
void QuickWidgetSink::updateName() {
|
||||
QString name = d->sink->properties().value("device.product.name").toString();
|
||||
ui->nameLabel->setText(this->fontMetrics().elidedText(name, Qt::ElideRight, SC_DPI(200)));
|
||||
}
|
||||
|
||||
void QuickWidgetSink::on_volumeSlider_valueChanged(int value) {
|
||||
qint64 factor = PulseAudioQt::normalVolume() / 100;
|
||||
qint64 newVolume = value * factor;
|
||||
d->sink->setVolume(newVolume);
|
||||
}
|
||||
|
||||
void QuickWidgetSink::on_actionMake_Default_triggered() {
|
||||
PulseAudioQt::Context::instance()->server()->setDefaultSink(d->sink);
|
||||
}
|
||||
|
||||
void QuickWidgetSink::on_actionMove_All_Applications_triggered() {
|
||||
for (PulseAudioQt::SinkInput* sinkInput : PulseAudioQt::Context::instance()->sinkInputs()) {
|
||||
sinkInput->setDeviceIndex(d->sink->index());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,14 +43,19 @@ class QuickWidgetSink : public QWidget {
|
|||
|
||||
void on_volumeSlider_valueChanged(int value);
|
||||
|
||||
void on_actionMake_Default_triggered();
|
||||
|
||||
void on_actionMove_All_Applications_triggered();
|
||||
|
||||
private:
|
||||
Ui::QuickWidgetSink* ui;
|
||||
QuickWidgetSinkPrivate* d;
|
||||
|
||||
void sinkInputAdded(PulseAudioQt::SinkInput* sinkInput);
|
||||
void updateVisibility();
|
||||
|
||||
void updateName();
|
||||
void updateVolume();
|
||||
void updateDefault();
|
||||
};
|
||||
|
||||
#endif // QUICKWIDGETSINK_H
|
||||
|
|
|
@ -40,7 +40,42 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="menuButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="application-menu"/>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionMake_Default">
|
||||
<property name="icon">
|
||||
<iconset theme="default"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Make Default</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMove_All_Applications">
|
||||
<property name="icon">
|
||||
<iconset theme="edit-select-all"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use for All Applications</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <Context>
|
||||
#include <the-libs_global.h>
|
||||
#include <QMenu>
|
||||
|
||||
struct QuickWidgetSinkInputPrivate {
|
||||
bool changingVolume = false;
|
||||
|
@ -29,6 +30,11 @@ struct QuickWidgetSinkInputPrivate {
|
|||
|
||||
QString pid;
|
||||
static QMultiMap<QString, QuickWidgetSinkInput*> sinkInputsByPid;
|
||||
|
||||
QMenu* menu;
|
||||
QMenu* devicesMenu;
|
||||
QMap<PulseAudioQt::Sink*, QAction*> sinkActions;
|
||||
QActionGroup* devicesGroup;
|
||||
};
|
||||
|
||||
QMultiMap<QString, QuickWidgetSinkInput*> QuickWidgetSinkInputPrivate::sinkInputsByPid = QMultiMap<QString, QuickWidgetSinkInput*>();
|
||||
|
@ -48,6 +54,21 @@ QuickWidgetSinkInput::QuickWidgetSinkInput(PulseAudioQt::SinkInput* sinkInput, Q
|
|||
updateVolume();
|
||||
updateProperties();
|
||||
|
||||
d->devicesGroup = new QActionGroup(this);
|
||||
d->devicesGroup->setExclusive(true);
|
||||
|
||||
d->devicesMenu = new QMenu();
|
||||
d->devicesMenu->setTitle(tr("Play on"));
|
||||
d->devicesMenu->setIcon(QIcon::fromTheme("audio-headphones"));
|
||||
|
||||
d->menu = new QMenu();
|
||||
d->menu->addMenu(d->devicesMenu);
|
||||
ui->menuButton->setMenu(d->menu);
|
||||
|
||||
connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkAdded, this, &QuickWidgetSinkInput::sinkAdded);
|
||||
connect(PulseAudioQt::Context::instance(), &PulseAudioQt::Context::sinkRemoved, this, &QuickWidgetSinkInput::sinkRemoved);
|
||||
for (PulseAudioQt::Sink* sink : PulseAudioQt::Context::instance()->sinks()) sinkAdded(sink);
|
||||
|
||||
this->setFixedWidth(SC_DPI(600));
|
||||
ui->nameLabel->setFixedWidth(SC_DPI(200));
|
||||
}
|
||||
|
@ -102,3 +123,35 @@ void QuickWidgetSinkInput::on_volumeSlider_valueChanged(int value) {
|
|||
|
||||
for (QuickWidgetSinkInput* sinkInputWidget : d->sinkInputsByPid.values(d->pid)) sinkInputWidget->d->sinkInput->setVolume(newVolume);
|
||||
}
|
||||
|
||||
void QuickWidgetSinkInput::sinkAdded(PulseAudioQt::Sink* sink) {
|
||||
QAction* action = new QAction(this);
|
||||
action->setCheckable(true);
|
||||
|
||||
connect(sink, &PulseAudioQt::Sink::propertiesChanged, this, [ = ] {
|
||||
action->setText(sink->properties().value("device.product.name").toString());
|
||||
});
|
||||
action->setText(sink->properties().value("device.product.name").toString());
|
||||
|
||||
connect(d->sinkInput, &PulseAudioQt::SinkInput::deviceIndexChanged, this, [ = ] {
|
||||
action->setChecked(sink->index() == d->sinkInput->deviceIndex());
|
||||
});
|
||||
action->setChecked(sink->index() == d->sinkInput->deviceIndex());
|
||||
|
||||
connect(action, &QAction::toggled, this, [ = ](bool checked) {
|
||||
if (checked) {
|
||||
for (QuickWidgetSinkInput* sinkInputWidget : d->sinkInputsByPid.values(d->pid)) sinkInputWidget->d->sinkInput->setDeviceIndex(sink->index());
|
||||
}
|
||||
});
|
||||
|
||||
d->devicesMenu->addAction(action);
|
||||
d->devicesGroup->addAction(action);
|
||||
d->sinkActions.insert(sink, action);
|
||||
}
|
||||
|
||||
void QuickWidgetSinkInput::sinkRemoved(PulseAudioQt::Sink* sink) {
|
||||
QAction* action = d->sinkActions.take(sink);
|
||||
d->devicesMenu->removeAction(action);
|
||||
d->devicesGroup->removeAction(action);
|
||||
action->deleteLater();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define QUICKWIDGETSINKINPUT_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <Sink>
|
||||
#include <SinkInput>
|
||||
|
||||
namespace Ui {
|
||||
|
@ -46,6 +47,9 @@ class QuickWidgetSinkInput : public QWidget {
|
|||
Ui::QuickWidgetSinkInput* ui;
|
||||
QuickWidgetSinkInputPrivate* d;
|
||||
|
||||
void sinkAdded(PulseAudioQt::Sink* sink);
|
||||
void sinkRemoved(PulseAudioQt::Sink* sink);
|
||||
|
||||
void updateVolume();
|
||||
void updateClient();
|
||||
void updateProperties();
|
||||
|
|
|
@ -43,6 +43,25 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="menuButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="application-menu"/>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
|
|
@ -53,4 +53,22 @@
|
|||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSink</name>
|
||||
<message>
|
||||
<source>Make Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use for All Applications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSinkInput</name>
|
||||
<message>
|
||||
<source>Play on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -55,11 +55,32 @@
|
|||
<context>
|
||||
<name>MicChunk</name>
|
||||
<message numerus="yes">
|
||||
<location filename="../micchunk.cpp" line="64"/>
|
||||
<location filename="../micchunk.cpp" line="66"/>
|
||||
<source>%n applications</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSink</name>
|
||||
<message>
|
||||
<location filename="../quickwidgetsink.ui" line="68"/>
|
||||
<source>Make Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../quickwidgetsink.ui" line="76"/>
|
||||
<source>Use for All Applications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSinkInput</name>
|
||||
<message>
|
||||
<location filename="../quickwidgetsinkinput.cpp" line="61"/>
|
||||
<source>Play on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -54,4 +54,22 @@
|
|||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSink</name>
|
||||
<message>
|
||||
<source>Make Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use for All Applications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSinkInput</name>
|
||||
<message>
|
||||
<source>Play on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -52,4 +52,22 @@
|
|||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSink</name>
|
||||
<message>
|
||||
<source>Make Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use for All Applications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSinkInput</name>
|
||||
<message>
|
||||
<source>Play on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -52,4 +52,22 @@
|
|||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSink</name>
|
||||
<message>
|
||||
<source>Make Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use for All Applications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSinkInput</name>
|
||||
<message>
|
||||
<source>Play on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -52,4 +52,22 @@
|
|||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSink</name>
|
||||
<message>
|
||||
<source>Make Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use for All Applications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSinkInput</name>
|
||||
<message>
|
||||
<source>Play on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -52,4 +52,22 @@
|
|||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSink</name>
|
||||
<message>
|
||||
<source>Make Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use for All Applications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QuickWidgetSinkInput</name>
|
||||
<message>
|
||||
<source>Play on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
Loading…
Reference in a new issue