PulseAudio Qt Bindings

streamrestore.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 David Rosca <[email protected]>
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 
15 namespace PulseAudioQt
16 {
17 StreamRestore::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 
28 StreamRestore::~StreamRestore()
29 {
30 }
31 
32 StreamRestorePrivate::StreamRestorePrivate(StreamRestore *q)
33  : q(q)
34 {
35 }
36 
37 StreamRestorePrivate::~StreamRestorePrivate()
38 {
39 }
40 
41 void StreamRestorePrivate::update(const pa_ext_stream_restore_info *info)
42 {
43  q->PulseObject::d->updatePulseObject(info);
44  m_cache.valid = false;
45 
46  const QString infoDevice = QString::fromUtf8(info->device);
47  if (m_device != infoDevice) {
48  m_device = infoDevice;
49  Q_EMIT q->deviceChanged();
50  }
51  if (m_muted != info->mute) {
52  m_muted = info->mute;
53  Q_EMIT q->mutedChanged();
54  }
55  if (!pa_cvolume_equal(&m_volume, &info->volume)) {
56  m_volume = info->volume;
57  Q_EMIT q->volumeChanged();
58  Q_EMIT q->channelVolumesChanged();
59  }
60  if (!pa_channel_map_equal(&m_channelMap, &info->channel_map)) {
61  m_channels.clear();
62  m_channels.reserve(info->channel_map.channels);
63  for (int i = 0; i < info->channel_map.channels; ++i) {
64  m_channels << QString::fromUtf8(pa_channel_position_to_pretty_string(info->channel_map.map[i]));
65  }
66  m_channelMap = info->channel_map;
67  Q_EMIT q->channelsChanged();
68  }
69 }
70 
71 QString StreamRestore::device() const
72 {
73  return d->m_device;
74 }
75 
76 void StreamRestore::setDevice(const QString &device)
77 {
78  if (d->m_cache.valid) {
79  if (d->m_cache.device != device) {
80  d->writeChanges(d->m_cache.volume, d->m_cache.muted, device);
81  }
82  } else {
83  if (d->m_device != device) {
84  d->writeChanges(d->m_volume, d->m_muted, device);
85  }
86  }
87 }
88 
89 qint64 StreamRestore::volume() const
90 {
91  return d->m_volume.values[0];
92 }
93 
94 void StreamRestore::setVolume(qint64 volume)
95 {
96  pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume;
97 
98  // If no channel exists force one. We need one to be able to control the volume
99  // See https://bugs.kde.org/show_bug.cgi?id=407397
100  if (vol.channels == 0) {
101  vol.channels = 1;
102  }
103 
104  for (int i = 0; i < vol.channels; ++i) {
105  vol.values[i] = volume;
106  }
107 
108  if (d->m_cache.valid) {
109  d->writeChanges(vol, d->m_cache.muted, d->m_cache.device);
110  } else {
111  d->writeChanges(vol, d->m_muted, d->m_device);
112  }
113 }
114 
115 bool StreamRestore::isMuted() const
116 {
117  return d->m_muted;
118 }
119 
120 void StreamRestore::setMuted(bool muted)
121 {
122  if (d->m_cache.valid) {
123  if (d->m_cache.muted != muted) {
124  d->writeChanges(d->m_cache.volume, muted, d->m_cache.device);
125  }
126  } else {
127  if (d->m_muted != muted) {
128  d->writeChanges(d->m_volume, muted, d->m_device);
129  }
130  }
131 }
132 
133 bool StreamRestore::hasVolume() const
134 {
135  return true;
136 }
137 
138 bool StreamRestore::isVolumeWritable() const
139 {
140  return true;
141 }
142 
143 QVector<QString> StreamRestore::channels() const
144 {
145  return d->m_channels;
146 }
147 
148 QVector<qreal> StreamRestore::channelVolumes() const
149 {
150  QVector<qreal> ret;
151  ret.reserve(d->m_volume.channels);
152  for (int i = 0; i < d->m_volume.channels; ++i) {
153  ret << d->m_volume.values[i];
154  }
155  return ret;
156 }
157 
158 void StreamRestore::setChannelVolume(int channel, qint64 volume)
159 {
160  Q_ASSERT(channel >= 0 && channel < d->m_volume.channels);
161  pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume;
162  vol.values[channel] = volume;
163 
164  if (d->m_cache.valid) {
165  d->writeChanges(vol, d->m_cache.muted, d->m_cache.device);
166  } else {
167  d->writeChanges(vol, d->m_muted, d->m_device);
168  }
169 }
170 
171 quint32 StreamRestore::deviceIndex() const
172 {
173  return PA_INVALID_INDEX;
174 }
175 
176 void StreamRestore::setDeviceIndex(quint32 deviceIndex)
177 {
178  Q_UNUSED(deviceIndex);
179  qCWarning(PULSEAUDIOQT) << "Not implemented";
180 }
181 
182 void StreamRestorePrivate::writeChanges(const pa_cvolume &volume, bool muted, const QString &device)
183 {
184  const QByteArray nameData = q->name().toUtf8();
185  const QByteArray deviceData = device.toUtf8();
186 
187  pa_ext_stream_restore_info info;
188  info.name = nameData.constData();
189  info.channel_map = m_channelMap;
190  info.volume = volume;
191  info.device = deviceData.isEmpty() ? nullptr : deviceData.constData();
192  info.mute = muted;
193 
194  // If no channel exists force one. We need one to be able to control the volume
195  // See https://bugs.kde.org/show_bug.cgi?id=407397
196  if (info.channel_map.channels == 0) {
197  info.channel_map.channels = 1;
198  info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
199  }
200 
201  m_cache.valid = true;
202  m_cache.volume = volume;
203  m_cache.muted = muted;
204  m_cache.device = device;
205 
206  Context::instance()->d->streamRestoreWrite(&info);
207 }
208 
209 quint32 StreamRestore::index() const
210 {
211  return d->m_index;
212 }
213 
214 } // PulseAudioQt
qreal volume()
QString fromUtf8(const char *str, int size)
void clear()
KGuiItem properties()
The primary namespace of PulseAudioQt.
Definition: card.cpp:16
QByteArray toUtf8() const const
void reserve(int size)
bool isEmpty() const const
const char * constData() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Fri Jun 9 2023 04:08:25 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.