File indexing completed on 2024-09-08 04:18:37
0001 /* 0002 SPDX-FileCopyrightText: 2016 David Rosca <nowrep@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "streamrestore.h" 0008 #include "context.h" 0009 #include "context_p.h" 0010 #include "streamrestore_p.h" 0011 0012 #include "debug.h" 0013 #include "pulseobject_p.h" 0014 0015 namespace PulseAudioQt 0016 { 0017 StreamRestore::StreamRestore(quint32 index, const QVariantMap &properties, QObject *parent) 0018 : PulseObject(parent) 0019 , d(new StreamRestorePrivate(this)) 0020 { 0021 memset(&d->m_volume, 0, sizeof(d->m_volume)); 0022 memset(&d->m_channelMap, 0, sizeof(d->m_channelMap)); 0023 0024 d->m_index = index; 0025 PulseObject::d->m_properties = properties; 0026 } 0027 0028 StreamRestore::~StreamRestore() 0029 { 0030 delete d; 0031 } 0032 0033 StreamRestorePrivate::StreamRestorePrivate(StreamRestore *q) 0034 : q(q) 0035 { 0036 } 0037 0038 StreamRestorePrivate::~StreamRestorePrivate() 0039 { 0040 } 0041 0042 void StreamRestorePrivate::update(const pa_ext_stream_restore_info *info) 0043 { 0044 q->PulseObject::d->updatePulseObject(info); 0045 m_cache.valid = false; 0046 0047 const QString infoDevice = QString::fromUtf8(info->device); 0048 if (m_device != infoDevice) { 0049 m_device = infoDevice; 0050 Q_EMIT q->deviceChanged(); 0051 } 0052 if (m_muted != info->mute) { 0053 m_muted = info->mute; 0054 Q_EMIT q->mutedChanged(); 0055 } 0056 if (!pa_cvolume_equal(&m_volume, &info->volume)) { 0057 m_volume = info->volume; 0058 Q_EMIT q->volumeChanged(); 0059 Q_EMIT q->channelVolumesChanged(); 0060 } 0061 if (!pa_channel_map_equal(&m_channelMap, &info->channel_map)) { 0062 m_channels.clear(); 0063 m_channels.reserve(info->channel_map.channels); 0064 for (int i = 0; i < info->channel_map.channels; ++i) { 0065 m_channels << QString::fromUtf8(pa_channel_position_to_pretty_string(info->channel_map.map[i])); 0066 } 0067 m_channelMap = info->channel_map; 0068 Q_EMIT q->channelsChanged(); 0069 } 0070 } 0071 0072 QString StreamRestore::device() const 0073 { 0074 return d->m_device; 0075 } 0076 0077 void StreamRestore::setDevice(const QString &device) 0078 { 0079 if (d->m_cache.valid) { 0080 if (d->m_cache.device != device) { 0081 d->writeChanges(d->m_cache.volume, d->m_cache.muted, device); 0082 } 0083 } else { 0084 if (d->m_device != device) { 0085 d->writeChanges(d->m_volume, d->m_muted, device); 0086 } 0087 } 0088 } 0089 0090 qint64 StreamRestore::volume() const 0091 { 0092 return d->m_volume.values[0]; 0093 } 0094 0095 void StreamRestore::setVolume(qint64 volume) 0096 { 0097 pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume; 0098 0099 // If no channel exists force one. We need one to be able to control the volume 0100 // See https://bugs.kde.org/show_bug.cgi?id=407397 0101 if (vol.channels == 0) { 0102 vol.channels = 1; 0103 } 0104 0105 for (int i = 0; i < vol.channels; ++i) { 0106 vol.values[i] = volume; 0107 } 0108 0109 if (d->m_cache.valid) { 0110 d->writeChanges(vol, d->m_cache.muted, d->m_cache.device); 0111 } else { 0112 d->writeChanges(vol, d->m_muted, d->m_device); 0113 } 0114 } 0115 0116 bool StreamRestore::isMuted() const 0117 { 0118 return d->m_muted; 0119 } 0120 0121 void StreamRestore::setMuted(bool muted) 0122 { 0123 if (d->m_cache.valid) { 0124 if (d->m_cache.muted != muted) { 0125 d->writeChanges(d->m_cache.volume, muted, d->m_cache.device); 0126 } 0127 } else { 0128 if (d->m_muted != muted) { 0129 d->writeChanges(d->m_volume, muted, d->m_device); 0130 } 0131 } 0132 } 0133 0134 bool StreamRestore::hasVolume() const 0135 { 0136 return true; 0137 } 0138 0139 bool StreamRestore::isVolumeWritable() const 0140 { 0141 return true; 0142 } 0143 0144 QVector<QString> StreamRestore::channels() const 0145 { 0146 return d->m_channels; 0147 } 0148 0149 QVector<qreal> StreamRestore::channelVolumes() const 0150 { 0151 QVector<qreal> ret; 0152 ret.reserve(d->m_volume.channels); 0153 for (int i = 0; i < d->m_volume.channels; ++i) { 0154 ret << d->m_volume.values[i]; 0155 } 0156 return ret; 0157 } 0158 0159 void StreamRestore::setChannelVolume(int channel, qint64 volume) 0160 { 0161 Q_ASSERT(channel >= 0 && channel < d->m_volume.channels); 0162 pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume; 0163 vol.values[channel] = volume; 0164 0165 if (d->m_cache.valid) { 0166 d->writeChanges(vol, d->m_cache.muted, d->m_cache.device); 0167 } else { 0168 d->writeChanges(vol, d->m_muted, d->m_device); 0169 } 0170 } 0171 0172 quint32 StreamRestore::deviceIndex() const 0173 { 0174 return PA_INVALID_INDEX; 0175 } 0176 0177 void StreamRestore::setDeviceIndex(quint32 deviceIndex) 0178 { 0179 Q_UNUSED(deviceIndex); 0180 qCWarning(PULSEAUDIOQT) << "Not implemented"; 0181 } 0182 0183 void StreamRestorePrivate::writeChanges(const pa_cvolume &volume, bool muted, const QString &device) 0184 { 0185 const QByteArray nameData = q->name().toUtf8(); 0186 const QByteArray deviceData = device.toUtf8(); 0187 0188 pa_ext_stream_restore_info info; 0189 info.name = nameData.constData(); 0190 info.channel_map = m_channelMap; 0191 info.volume = volume; 0192 info.device = deviceData.isEmpty() ? nullptr : deviceData.constData(); 0193 info.mute = muted; 0194 0195 // If no channel exists force one. We need one to be able to control the volume 0196 // See https://bugs.kde.org/show_bug.cgi?id=407397 0197 if (info.channel_map.channels == 0) { 0198 info.channel_map.channels = 1; 0199 info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO; 0200 } 0201 0202 m_cache.valid = true; 0203 m_cache.volume = volume; 0204 m_cache.muted = muted; 0205 m_cache.device = device; 0206 0207 Context::instance()->d->streamRestoreWrite(&info); 0208 } 0209 0210 quint32 StreamRestore::index() const 0211 { 0212 return d->m_index; 0213 } 0214 0215 } // PulseAudioQt