PulseAudio Qt Bindings

streamrestore.cpp
1/*
2 SPDX-FileCopyrightText: 2016 David Rosca <nowrep@gmail.com>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "streamrestore.h"
8#include "context.h"
9#include "context_p.h"
10#include "streamrestore_p.h"
11
12#include "debug.h"
13#include "pulseobject_p.h"
14
15namespace PulseAudioQt
16{
17StreamRestore::StreamRestore(quint32 index, const QVariantMap &properties, QObject *parent)
18 : PulseObject(parent)
19 , d(new StreamRestorePrivate(this))
20{
21 memset(&d->m_volume, 0, sizeof(d->m_volume));
22 memset(&d->m_channelMap, 0, sizeof(d->m_channelMap));
23
24 d->m_index = index;
25 PulseObject::d->m_properties = properties;
26}
27
28StreamRestore::~StreamRestore()
29{
30 delete d;
31}
32
33StreamRestorePrivate::StreamRestorePrivate(StreamRestore *q)
34 : q(q)
35{
36}
37
38StreamRestorePrivate::~StreamRestorePrivate()
39{
40}
41
42void StreamRestorePrivate::update(const pa_ext_stream_restore_info *info)
43{
44 q->PulseObject::d->updatePulseObject(info);
45 m_cache.valid = false;
46
47 const QString infoDevice = QString::fromUtf8(info->device);
48 if (m_device != infoDevice) {
49 m_device = infoDevice;
50 Q_EMIT q->deviceChanged();
51 }
52 if (m_muted != info->mute) {
53 m_muted = info->mute;
54 Q_EMIT q->mutedChanged();
55 }
56 if (!pa_cvolume_equal(&m_volume, &info->volume)) {
57 m_volume = info->volume;
58 Q_EMIT q->volumeChanged();
59 Q_EMIT q->channelVolumesChanged();
60 }
61 if (!pa_channel_map_equal(&m_channelMap, &info->channel_map)) {
62 m_channels.clear();
63 m_channels.reserve(info->channel_map.channels);
64 for (int i = 0; i < info->channel_map.channels; ++i) {
65 m_channels << QString::fromUtf8(pa_channel_position_to_pretty_string(info->channel_map.map[i]));
66 }
67 m_channelMap = info->channel_map;
68 Q_EMIT q->channelsChanged();
69 }
70}
71
72QString StreamRestore::device() const
73{
74 return d->m_device;
75}
76
77void StreamRestore::setDevice(const QString &device)
78{
79 if (d->m_cache.valid) {
80 if (d->m_cache.device != device) {
81 d->writeChanges(d->m_cache.volume, d->m_cache.muted, device);
82 }
83 } else {
84 if (d->m_device != device) {
85 d->writeChanges(d->m_volume, d->m_muted, device);
86 }
87 }
88}
89
90qint64 StreamRestore::volume() const
91{
92 // FIXME: workaround for pipewire not supporting stream restore subscription
93 // revert when fix is released
94 // https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3805
95 if (d->m_cache.valid) {
96 return d->m_cache.volume.values[0];
97 } else {
98 return d->m_volume.values[0];
99 }
100}
101
102void StreamRestore::setVolume(qint64 volume)
103{
104 pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume;
105
106 // If no channel exists force one. We need one to be able to control the volume
107 // See https://bugs.kde.org/show_bug.cgi?id=407397
108 if (vol.channels == 0) {
109 vol.channels = 1;
110 }
111
112 for (int i = 0; i < vol.channels; ++i) {
113 vol.values[i] = volume;
114 }
115
116 if (d->m_cache.valid) {
117 qCDebug(PULSEAUDIOQT) << "Changing cached volume of StreamRestore" << name() << " to " << volume;
118 d->writeChanges(vol, d->m_cache.muted, d->m_cache.device);
119 } else {
120 qCDebug(PULSEAUDIOQT) << "Changing uncached volume of StreamRestore" << name() << " to " << volume;
121 d->writeChanges(vol, d->m_muted, d->m_device);
122 }
123}
124
125bool StreamRestore::isMuted() const
126{
127 // FIXME: workaround for pipewire not supporting stream restore subscription
128 // revert when fix is released
129 // https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3805
130 if (d->m_cache.valid) {
131 return d->m_cache.muted;
132 } else {
133 return d->m_muted;
134 }
135}
136
137void StreamRestore::setMuted(bool muted)
138{
139 if (d->m_cache.valid) {
140 if (d->m_cache.muted != muted) {
141 d->writeChanges(d->m_cache.volume, muted, d->m_cache.device);
142 }
143 } else {
144 if (d->m_muted != muted) {
145 d->writeChanges(d->m_volume, muted, d->m_device);
146 }
147 }
148}
149
150bool StreamRestore::hasVolume() const
151{
152 return true;
153}
154
155bool StreamRestore::isVolumeWritable() const
156{
157 return true;
158}
159
160QStringList StreamRestore::channels() const
161{
162 return d->m_channels;
163}
164
165QList<qreal> StreamRestore::channelVolumes() const
166{
167 QList<qreal> ret;
168 ret.reserve(d->m_volume.channels);
169 for (int i = 0; i < d->m_volume.channels; ++i) {
170 ret << d->m_volume.values[i];
171 }
172 return ret;
173}
174
175void StreamRestore::setChannelVolume(int channel, qint64 volume)
176{
177 Q_ASSERT(channel >= 0 && channel < d->m_volume.channels);
178 pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume;
179 vol.values[channel] = volume;
180
181 if (d->m_cache.valid) {
182 d->writeChanges(vol, d->m_cache.muted, d->m_cache.device);
183 } else {
184 d->writeChanges(vol, d->m_muted, d->m_device);
185 }
186}
187
188quint32 StreamRestore::deviceIndex() const
189{
190 return PA_INVALID_INDEX;
191}
192
193void StreamRestore::setDeviceIndex(quint32 deviceIndex)
194{
195 Q_UNUSED(deviceIndex);
196 qCWarning(PULSEAUDIOQT) << "Not implemented";
197}
198
199void StreamRestorePrivate::writeChanges(const pa_cvolume &volume, bool muted, const QString &device)
200{
201 const QByteArray nameData = q->name().toUtf8();
202 const QByteArray deviceData = device.toUtf8();
203
204 pa_ext_stream_restore_info info;
205 info.name = nameData.constData();
206 info.channel_map = m_channelMap;
207 info.volume = volume;
208 info.device = deviceData.isEmpty() ? nullptr : deviceData.constData();
209 info.mute = muted;
210
211 // If no channel exists force one. We need one to be able to control the volume
212 // See https://bugs.kde.org/show_bug.cgi?id=407397
213 if (info.channel_map.channels == 0) {
214 info.channel_map.channels = 1;
215 info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
216 }
217
218 m_cache.valid = true;
219 m_cache.volume = volume;
220 m_cache.muted = muted;
221 m_cache.device = device;
222
223 Context::instance()->d->streamRestoreWrite(&info);
224}
225
226quint32 StreamRestore::index() const
227{
228 return d->m_index;
229}
230
231} // PulseAudioQt
QString name(StandardAction id)
KGuiItem properties()
The primary namespace of PulseAudioQt.
Definition card.cpp:17
const char * constData() const const
bool isEmpty() const const
void reserve(qsizetype size)
QString fromUtf8(QByteArrayView str)
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:12:38 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.