11#include <QAbstractEventDispatcher>
12#include <QDBusConnection>
13#include <QDBusServiceWatcher>
14#include <QGuiApplication>
26#include "sourceoutput.h"
27#include "streamrestore.h"
31#include "streamrestore_p.h"
37 return PA_VOLUME_NORM;
42 return PA_VOLUME_MUTED;
52 return PA_VOLUME_UI_MAX;
55QString ContextPrivate::s_applicationId;
59static bool isGoodState(
int eol)
76static void sink_cb(pa_context *context,
const pa_sink_info *info,
int eol,
void *data)
78 if (!isGoodState(eol))
82 static_cast<ContextPrivate *
>(data)->sinkCallback(info);
85static void sink_input_callback(pa_context *context,
const pa_sink_input_info *info,
int eol,
void *data)
87 if (!isGoodState(eol))
90 if (qstrcmp(info->name,
"pulsesink probe") == 0) {
93 if (
const char *
id = pa_proplist_gets(info->proplist,
"module-stream-restore.id")) {
94 if (qstrcmp(
id,
"sink-input-by-media-role:event") == 0) {
95 qCDebug(PULSEAUDIOQT) <<
"Ignoring event role sink input.";
101 static_cast<ContextPrivate *
>(data)->sinkInputCallback(info);
104static void source_cb(pa_context *context,
const pa_source_info *info,
int eol,
void *data)
106 if (!isGoodState(eol))
109 if (info->monitor_of_sink != PA_INVALID_INDEX)
113 static_cast<ContextPrivate *
>(data)->sourceCallback(info);
116static void source_output_cb(pa_context *context,
const pa_source_output_info *info,
int eol,
void *data)
118 if (!isGoodState(eol))
121 if (
const char *app = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_ID)) {
122 if (strcmp(app,
"org.PulseAudio.pavucontrol") == 0
123 || strcmp(app,
"org.gnome.VolumeControl") == 0
124 || strcmp(app,
"org.kde.kmixd") == 0
125 || strcmp(app,
"org.kde.plasma-pa") == 0)
130 static_cast<ContextPrivate *
>(data)->sourceOutputCallback(info);
133static void client_cb(pa_context *context,
const pa_client_info *info,
int eol,
void *data)
135 if (!isGoodState(eol))
139 static_cast<ContextPrivate *
>(data)->clientCallback(info);
142static void card_cb(pa_context *context,
const pa_card_info *info,
int eol,
void *data)
144 if (!isGoodState(eol))
148 static_cast<ContextPrivate *
>(data)->cardCallback(info);
151static void module_info_list_cb(pa_context *context,
const pa_module_info *info,
int eol,
void *data)
153 if (!isGoodState(eol))
157 static_cast<ContextPrivate *
>(data)->moduleCallback(info);
160static void server_cb(pa_context *context,
const pa_server_info *info,
void *data)
167 qCWarning(PULSEAUDIOQT) <<
"server_cb() called without info!";
170 static_cast<ContextPrivate *
>(data)->serverCallback(info);
173static void context_state_callback(pa_context *context,
void *data)
176 static_cast<ContextPrivate *
>(data)->contextStateCallback(context);
179static void subscribe_cb(pa_context *context, pa_subscription_event_type_t type, uint32_t index,
void *data)
182 static_cast<ContextPrivate *
>(data)->subscribeCallback(context, type, index);
185static void ext_stream_restore_read_cb(pa_context *context,
const pa_ext_stream_restore_info *info,
int eol,
void *data)
187 if (!isGoodState(eol)) {
192 static_cast<ContextPrivate *
>(data)->streamRestoreCallback(info);
195static void ext_stream_restore_subscribe_cb(pa_context *context,
void *data)
199 if (!PAOperation(pa_ext_stream_restore_read(context, ext_stream_restore_read_cb, data))) {
200 qCWarning(PULSEAUDIOQT) <<
"pa_ext_stream_restore_read() failed";
204static void ext_stream_restore_change_sink_cb(pa_context *context,
const pa_ext_stream_restore_info *info,
int eol,
void *data)
206 if (!isGoodState(eol)) {
211 if (qstrncmp(info->name,
"sink-input-by", 13) == 0) {
212 ContextPrivate *contextp =
static_cast<ContextPrivate *
>(data);
213 const QByteArray deviceData = contextp->m_newDefaultSink.toUtf8();
214 pa_ext_stream_restore_info newinfo;
215 newinfo.name = info->name;
216 newinfo.channel_map = info->channel_map;
217 newinfo.volume = info->volume;
218 newinfo.mute = info->mute;
220 contextp->streamRestoreWrite(&newinfo);
224static void ext_stream_restore_change_source_cb(pa_context *context,
const pa_ext_stream_restore_info *info,
int eol,
void *data)
226 if (!isGoodState(eol)) {
231 if (qstrncmp(info->name,
"source-output-by", 16) == 0) {
232 ContextPrivate *contextp =
static_cast<ContextPrivate *
>(data);
233 const QByteArray deviceData = contextp->m_newDefaultSource.toUtf8();
234 pa_ext_stream_restore_info newinfo;
235 newinfo.name = info->name;
236 newinfo.channel_map = info->channel_map;
237 newinfo.volume = info->volume;
238 newinfo.mute = info->mute;
240 contextp->streamRestoreWrite(&newinfo);
248Context::Context(
QObject *parent)
250 , d(new ContextPrivate(this))
252 d->m_server =
new Server(
this);
253 d->m_context =
nullptr;
254 d->m_mainloop =
nullptr;
256 d->connectToDaemon();
261 d->connectToDaemon();
265 d->connectToDaemon();
266 d->checkConnectTries();
269 connect(&d->m_sinks, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
270 Q_EMIT sinkAdded(static_cast<Sink *>(object));
272 connect(&d->m_sinks, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
273 Q_EMIT sinkRemoved(static_cast<Sink *>(object));
276 connect(&d->m_sinkInputs, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
277 Q_EMIT sinkInputAdded(static_cast<SinkInput *>(object));
279 connect(&d->m_sinkInputs, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
280 Q_EMIT sinkInputRemoved(static_cast<SinkInput *>(object));
283 connect(&d->m_sources, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
284 Q_EMIT sourceAdded(static_cast<Source *>(object));
286 connect(&d->m_sources, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
287 Q_EMIT sourceRemoved(static_cast<Source *>(object));
290 connect(&d->m_sourceOutputs, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
291 Q_EMIT sourceOutputAdded(static_cast<SourceOutput *>(object));
293 connect(&d->m_sourceOutputs, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
294 Q_EMIT sourceOutputRemoved(static_cast<SourceOutput *>(object));
297 connect(&d->m_clients, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
298 Q_EMIT clientAdded(static_cast<Client *>(object));
300 connect(&d->m_clients, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
301 Q_EMIT clientRemoved(static_cast<Client *>(object));
304 connect(&d->m_cards, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
305 Q_EMIT cardAdded(static_cast<Card *>(object));
307 connect(&d->m_cards, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
308 Q_EMIT cardRemoved(static_cast<Card *>(object));
311 connect(&d->m_modules, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
312 Q_EMIT moduleAdded(static_cast<Module *>(object));
314 connect(&d->m_modules, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
315 Q_EMIT moduleRemoved(static_cast<Module *>(object));
318 connect(&d->m_streamRestores, &MapBaseQObject::added,
this, [
this](
int,
QObject *
object) {
319 Q_EMIT streamRestoreAdded(static_cast<StreamRestore *>(object));
321 connect(&d->m_streamRestores, &MapBaseQObject::removed,
this, [
this](
int,
QObject *
object) {
322 Q_EMIT streamRestoreRemoved(static_cast<StreamRestore *>(object));
326ContextPrivate::ContextPrivate(Context *q)
336ContextPrivate::~ContextPrivate()
339 pa_context_unref(m_context);
344 pa_glib_mainloop_free(m_mainloop);
345 m_mainloop =
nullptr;
351Context *Context::instance()
353 static std::unique_ptr<Context> context(
new Context);
354 return context.get();
357void ContextPrivate::subscribeCallback(pa_context *context, pa_subscription_event_type_t type, uint32_t index)
359 Q_ASSERT(context == m_context);
361 switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
362 case PA_SUBSCRIPTION_EVENT_SINK:
363 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
364 m_sinks.removeEntry(index);
366 if (!PAOperation(pa_context_get_sink_info_by_index(context, index, sink_cb,
this))) {
367 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_sink_info_by_index() failed";
373 case PA_SUBSCRIPTION_EVENT_SOURCE:
374 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
375 m_sources.removeEntry(index);
377 if (!PAOperation(pa_context_get_source_info_by_index(context, index, source_cb,
this))) {
378 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_source_info_by_index() failed";
384 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
385 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
386 m_sinkInputs.removeEntry(index);
388 if (!PAOperation(pa_context_get_sink_input_info(context, index, sink_input_callback,
this))) {
389 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_sink_input_info() failed";
395 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
396 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
397 m_sourceOutputs.removeEntry(index);
399 if (!PAOperation(pa_context_get_source_output_info(context, index, source_output_cb,
this))) {
400 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_sink_input_info() failed";
406 case PA_SUBSCRIPTION_EVENT_CLIENT:
407 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
408 m_clients.removeEntry(index);
410 if (!PAOperation(pa_context_get_client_info(context, index, client_cb,
this))) {
411 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_client_info() failed";
417 case PA_SUBSCRIPTION_EVENT_CARD:
418 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
419 m_cards.removeEntry(index);
421 if (!PAOperation(pa_context_get_card_info_by_index(context, index, card_cb,
this))) {
422 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_card_info_by_index() failed";
428 case PA_SUBSCRIPTION_EVENT_MODULE:
429 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
430 m_modules.removeEntry(index);
432 if (!PAOperation(pa_context_get_module_info_list(context, module_info_list_cb,
this))) {
433 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_module_info_list() failed";
439 case PA_SUBSCRIPTION_EVENT_SERVER:
440 if (!PAOperation(pa_context_get_server_info(context, server_cb,
this))) {
441 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_server_info() failed";
448void ContextPrivate::contextStateCallback(pa_context *c)
450 qCDebug(PULSEAUDIOQT) <<
"state callback";
451 pa_context_state_t state = pa_context_get_state(c);
452 if (state == PA_CONTEXT_READY) {
453 qCDebug(PULSEAUDIOQT) <<
"ready, stopping connect timer";
454 m_connectTimer.stop();
457 if (m_context == c) {
458 pa_context_set_subscribe_callback(c, subscribe_cb,
this);
461 pa_context_subscribe(c,
462 (pa_subscription_mask_t)(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_CLIENT
463 | PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
464 | PA_SUBSCRIPTION_MASK_CARD | PA_SUBSCRIPTION_MASK_MODULE | PA_SUBSCRIPTION_MASK_SERVER),
467 qCWarning(PULSEAUDIOQT) <<
"pa_context_subscribe() failed";
472 if (!PAOperation(pa_context_get_sink_info_list(c, sink_cb,
this))) {
473 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_sink_info_list() failed";
477 if (!PAOperation(pa_context_get_source_info_list(c, source_cb,
this))) {
478 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_source_info_list() failed";
482 if (!PAOperation(pa_context_get_client_info_list(c, client_cb,
this))) {
483 qCWarning(PULSEAUDIOQT) <<
"pa_context_client_info_list() failed";
487 if (!PAOperation(pa_context_get_card_info_list(c, card_cb,
this))) {
488 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_card_info_list() failed";
492 if (!PAOperation(pa_context_get_sink_input_info_list(c, sink_input_callback,
this))) {
493 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_sink_input_info_list() failed";
497 if (!PAOperation(pa_context_get_source_output_info_list(c, source_output_cb,
this))) {
498 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_source_output_info_list() failed";
502 if (!PAOperation(pa_context_get_module_info_list(c, module_info_list_cb,
this))) {
503 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_module_info_list() failed";
507 if (!PAOperation(pa_context_get_server_info(c, server_cb,
this))) {
508 qCWarning(PULSEAUDIOQT) <<
"pa_context_get_server_info() failed";
512 if (PAOperation(pa_ext_stream_restore_read(c, ext_stream_restore_read_cb,
this))) {
513 pa_ext_stream_restore_set_subscribe_cb(c, ext_stream_restore_subscribe_cb,
this);
514 PAOperation(pa_ext_stream_restore_subscribe(c, 1,
nullptr,
this));
516 qCWarning(PULSEAUDIOQT) <<
"Failed to initialize stream_restore extension";
518 }
else if (!PA_CONTEXT_IS_GOOD(state)) {
519 qCWarning(PULSEAUDIOQT) <<
"context kaput";
521 pa_context_unref(m_context);
525 qCDebug(PULSEAUDIOQT) <<
"Starting connect timer";
526 m_connectTimer.start(std::chrono::seconds(5));
530void ContextPrivate::sinkCallback(
const pa_sink_info *info)
533 m_sinks.updateEntry(info, q);
536void ContextPrivate::sinkInputCallback(
const pa_sink_input_info *info)
538 m_sinkInputs.updateEntry(info, q);
541void ContextPrivate::sourceCallback(
const pa_source_info *info)
543 m_sources.updateEntry(info, q);
546void ContextPrivate::sourceOutputCallback(
const pa_source_output_info *info)
548 m_sourceOutputs.updateEntry(info, q);
551void ContextPrivate::clientCallback(
const pa_client_info *info)
553 m_clients.updateEntry(info, q);
556void ContextPrivate::cardCallback(
const pa_card_info *info)
558 m_cards.updateEntry(info, q);
561void ContextPrivate::moduleCallback(
const pa_module_info *info)
563 m_modules.updateEntry(info, q);
566void ContextPrivate::streamRestoreCallback(
const pa_ext_stream_restore_info *info)
568 if (qstrcmp(info->name,
"sink-input-by-media-role:event") != 0) {
572 const int eventRoleIndex = 1;
573 StreamRestore *obj = qobject_cast<StreamRestore *>(m_streamRestores.data().value(eventRoleIndex));
577 props.insert(QStringLiteral(
"application.icon_name"), QStringLiteral(
"preferences-desktop-notification"));
578 obj =
new StreamRestore(eventRoleIndex, props, q);
579 obj->d->update(info);
580 m_streamRestores.insert(obj);
582 obj->d->update(info);
586void ContextPrivate::serverCallback(
const pa_server_info *info)
588 m_server->d->update(info);
591void Context::setCardProfile(quint32 index,
const QString &profile)
596 qCDebug(PULSEAUDIOQT) << index << profile;
597 if (!PAOperation(pa_context_set_card_profile_by_index(d->m_context, index, profile.toUtf8().constData(),
nullptr,
nullptr))) {
598 qCWarning(PULSEAUDIOQT) <<
"pa_context_set_card_profile_by_index failed";
603void Context::setDefaultSink(
const QString &name)
609 if (!PAOperation(pa_context_set_default_sink(d->m_context, nameData.
constData(),
nullptr,
nullptr))) {
610 qCWarning(PULSEAUDIOQT) <<
"pa_context_set_default_sink failed";
614 d->m_newDefaultSink =
name;
615 if (!PAOperation(pa_ext_stream_restore_read(d->m_context, ext_stream_restore_change_sink_cb, d))) {
616 qCWarning(PULSEAUDIOQT) <<
"pa_ext_stream_restore_read failed";
620void Context::setDefaultSource(
const QString &name)
626 if (!PAOperation(pa_context_set_default_source(d->m_context, nameData.
constData(),
nullptr,
nullptr))) {
627 qCWarning(PULSEAUDIOQT) <<
"pa_context_set_default_source failed";
631 d->m_newDefaultSource =
name;
632 if (!PAOperation(pa_ext_stream_restore_read(d->m_context, ext_stream_restore_change_source_cb, d))) {
633 qCWarning(PULSEAUDIOQT) <<
"pa_ext_stream_restore_read failed";
637void ContextPrivate::streamRestoreWrite(
const pa_ext_stream_restore_info *info)
642 if (!PAOperation(pa_ext_stream_restore_write(m_context, PA_UPDATE_REPLACE, info, 1,
true,
nullptr,
nullptr))) {
643 qCWarning(PULSEAUDIOQT) <<
"pa_ext_stream_restore_write failed";
647void ContextPrivate::connectToDaemon()
655 qCWarning(PULSEAUDIOQT) <<
"Disabling PulseAudio integration for lack of GLib event loop";
659 qCDebug(PULSEAUDIOQT) <<
"Attempting connection to PulseAudio sound daemon";
661 m_mainloop = pa_glib_mainloop_new(
nullptr);
662 Q_ASSERT(m_mainloop);
665 pa_mainloop_api *api = pa_glib_mainloop_get_api(m_mainloop);
668 pa_proplist *proplist = pa_proplist_new();
670 if (!s_applicationId.isEmpty()) {
671 pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, s_applicationId.toUtf8().constData());
676 m_context = pa_context_new_with_proplist(api,
nullptr, proplist);
677 pa_proplist_free(proplist);
680 if (pa_context_connect(m_context, NULL, PA_CONTEXT_NOFAIL,
nullptr) < 0) {
681 pa_context_unref(m_context);
682 pa_glib_mainloop_free(m_mainloop);
684 m_mainloop =
nullptr;
687 pa_context_set_state_callback(m_context, &context_state_callback,
this);
690void ContextPrivate::checkConnectTries()
692 if (++m_connectTries == 5) {
693 qCWarning(PULSEAUDIOQT) <<
"Giving up after" << m_connectTries <<
"tries to connect";
694 m_connectTimer.stop();
698void ContextPrivate::reset()
701 m_sinkInputs.reset();
703 m_sourceOutputs.reset();
707 m_streamRestores.reset();
712bool Context::isValid()
714 return d->m_context && d->m_mainloop;
719 return d->m_sinks.
data();
724 return d->m_sinkInputs.
data();
729 return d->m_sources.
data();
734 return d->m_sourceOutputs.
data();
739 return d->m_clients.
data();
744 return d->m_cards.
data();
749 return d->m_modules.
data();
754 return d->m_streamRestores.
data();
757Server *Context::server()
const
762void ContextPrivate::setGenericVolume(
767 const std::function<pa_operation *(pa_context *, uint32_t,
const pa_cvolume *, pa_context_success_cb_t,
void *)> &pa_set_volume)
772 newVolume = qBound<qint64>(0, newVolume, PA_VOLUME_MAX);
773 pa_cvolume newCVolume = cVolume;
775 const qint64 orig = pa_cvolume_max(&cVolume);
776 const qint64 diff = newVolume - orig;
777 for (
int i = 0; i < newCVolume.channels; ++i) {
778 const qint64 channel = newCVolume.values[i];
779 const qint64 channelDiff = orig == 0 ? diff : diff * channel / orig;
780 newCVolume.values[i] = qBound<qint64>(0, newCVolume.values[i] + channelDiff, PA_VOLUME_MAX);
783 Q_ASSERT(newCVolume.channels > channel);
784 newCVolume.values[channel] = newVolume;
786 if (!PAOperation(pa_set_volume(m_context, index, &newCVolume,
nullptr,
nullptr))) {
787 qCWarning(PULSEAUDIOQT) <<
"pa_set_volume failed";
792void ContextPrivate::setGenericMute(quint32 index,
794 const std::function<pa_operation *(pa_context *, uint32_t,
int, pa_context_success_cb_t,
void *)> &pa_set_mute)
799 if (!PAOperation(pa_set_mute(m_context, index, mute,
nullptr,
nullptr))) {
800 qCWarning(PULSEAUDIOQT) <<
"pa_set_mute failed";
805void ContextPrivate::setGenericPort(quint32 index,
807 const std::function<pa_operation *(pa_context *, uint32_t,
const char *, pa_context_success_cb_t,
void *)> &pa_set_port)
812 if (!PAOperation(pa_set_port(m_context, index, portName.
toUtf8().
constData(),
nullptr,
nullptr))) {
813 qCWarning(PULSEAUDIOQT) <<
"pa_set_port failed";
818void ContextPrivate::setGenericDeviceForStream(
821 const std::function<pa_operation *(pa_context *, uint32_t, uint32_t, pa_context_success_cb_t,
void *)> &pa_move_stream_to_device)
826 if (!PAOperation(pa_move_stream_to_device(m_context, streamIndex, deviceIndex,
nullptr,
nullptr))) {
827 qCWarning(PULSEAUDIOQT) <<
"pa_move_stream_to_device failed";
832void ContextPrivate::setGenericVolumes(
836 const std::function<pa_operation *(pa_context *, uint32_t,
const pa_cvolume *, pa_context_success_cb_t,
void *)> &pa_set_volume)
841 Q_ASSERT(channelVolumes.
count() == cVolume.channels);
843 pa_cvolume newCVolume = cVolume;
844 for (
int i = 0; i < channelVolumes.
count(); ++i) {
845 newCVolume.values[i] = qBound<qint64>(0, channelVolumes.
at(i), PA_VOLUME_MAX);
848 if (!PAOperation(pa_set_volume(m_context, index, &newCVolume,
nullptr,
nullptr))) {
849 qCWarning(PULSEAUDIOQT) <<
"pa_set_volume failed";
854void Context::setApplicationId(
const QString &applicationId)
856 ContextPrivate::s_applicationId = applicationId;
859pa_context *Context::context()
const
QString name(StandardShortcut id)
The primary namespace of PulseAudioQt.
qint64 normalVolume()
The normal volume (100%, 0 dB).
qint64 maximumUIVolume()
The maximum volume suitable to display in a UI.
qint64 minimumVolume()
The minimum volume (0%).
qint64 maximumVolume()
The maximum volume PulseAudio can store.
QAbstractEventDispatcher * instance(QThread *thread)
const char * constData() const const
QDBusConnection sessionBus()
void serviceRegistered(const QString &serviceName)
const_reference at(qsizetype i) const const
qsizetype count() const const
QByteArray toUtf8() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)