File indexing completed on 2024-12-01 13:40:43
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 "debug.h" 0010 0011 namespace QPulseAudio 0012 { 0013 StreamRestore::StreamRestore(quint32 index, const QVariantMap &properties, QObject *parent) 0014 : PulseObject(parent) 0015 { 0016 memset(&m_volume, 0, sizeof(m_volume)); 0017 memset(&m_channelMap, 0, sizeof(m_channelMap)); 0018 0019 m_index = index; 0020 m_properties = properties; 0021 } 0022 0023 void StreamRestore::update(const pa_ext_stream_restore_info *info) 0024 { 0025 m_cache.valid = false; 0026 const QString infoName = QString::fromUtf8(info->name); 0027 if (m_name != infoName) { 0028 m_name = infoName; 0029 Q_EMIT nameChanged(); 0030 } 0031 const QString infoDevice = QString::fromUtf8(info->device); 0032 if (m_device != infoDevice) { 0033 m_device = infoDevice; 0034 Q_EMIT deviceChanged(); 0035 } 0036 if (m_muted != info->mute) { 0037 m_muted = info->mute; 0038 Q_EMIT mutedChanged(); 0039 } 0040 if (!pa_cvolume_equal(&m_volume, &info->volume)) { 0041 m_volume = info->volume; 0042 Q_EMIT volumeChanged(); 0043 Q_EMIT channelVolumesChanged(); 0044 } 0045 if (!pa_channel_map_equal(&m_channelMap, &info->channel_map)) { 0046 m_channels.clear(); 0047 m_channels.reserve(info->channel_map.channels); 0048 for (int i = 0; i < info->channel_map.channels; ++i) { 0049 m_channels << QString::fromUtf8(pa_channel_position_to_pretty_string(info->channel_map.map[i])); 0050 } 0051 m_channelMap = info->channel_map; 0052 Q_EMIT channelsChanged(); 0053 } 0054 } 0055 0056 QString StreamRestore::name() const 0057 { 0058 return m_name; 0059 } 0060 0061 QString StreamRestore::device() const 0062 { 0063 return m_device; 0064 } 0065 0066 void StreamRestore::setDevice(const QString &device) 0067 { 0068 if (m_cache.valid) { 0069 if (m_cache.device != device) { 0070 writeChanges(m_cache.volume, m_cache.muted, device); 0071 } 0072 } else { 0073 if (m_device != device) { 0074 writeChanges(m_volume, m_muted, device); 0075 } 0076 } 0077 } 0078 0079 qint64 StreamRestore::volume() const 0080 { 0081 return m_volume.values[0]; 0082 } 0083 0084 void StreamRestore::setVolume(qint64 volume) 0085 { 0086 pa_cvolume vol = m_cache.valid ? m_cache.volume : m_volume; 0087 0088 // If no channel exists force one. We need one to be able to control the volume 0089 // See https://bugs.kde.org/show_bug.cgi?id=407397 0090 if (vol.channels == 0) { 0091 vol.channels = 1; 0092 } 0093 0094 for (int i = 0; i < vol.channels; ++i) { 0095 vol.values[i] = volume; 0096 } 0097 0098 if (m_cache.valid) { 0099 writeChanges(vol, m_cache.muted, m_cache.device); 0100 } else { 0101 writeChanges(vol, m_muted, m_device); 0102 } 0103 } 0104 0105 bool StreamRestore::isMuted() const 0106 { 0107 return m_muted; 0108 } 0109 0110 void StreamRestore::setMuted(bool muted) 0111 { 0112 if (m_cache.valid) { 0113 if (m_cache.muted != muted) { 0114 writeChanges(m_cache.volume, muted, m_cache.device); 0115 } 0116 } else { 0117 if (m_muted != muted) { 0118 writeChanges(m_volume, muted, m_device); 0119 } 0120 } 0121 } 0122 0123 bool StreamRestore::hasVolume() const 0124 { 0125 return true; 0126 } 0127 0128 bool StreamRestore::isVolumeWritable() const 0129 { 0130 return true; 0131 } 0132 0133 QStringList StreamRestore::channels() const 0134 { 0135 return m_channels; 0136 } 0137 0138 QList<qreal> StreamRestore::channelVolumes() const 0139 { 0140 QList<qreal> ret; 0141 ret.reserve(m_volume.channels); 0142 for (int i = 0; i < m_volume.channels; ++i) { 0143 ret << m_volume.values[i]; 0144 } 0145 return ret; 0146 } 0147 0148 void StreamRestore::setChannelVolume(int channel, qint64 volume) 0149 { 0150 Q_ASSERT(channel >= 0 && channel < m_volume.channels); 0151 pa_cvolume vol = m_cache.valid ? m_cache.volume : m_volume; 0152 vol.values[channel] = volume; 0153 0154 if (m_cache.valid) { 0155 writeChanges(vol, m_cache.muted, m_cache.device); 0156 } else { 0157 writeChanges(vol, m_muted, m_device); 0158 } 0159 } 0160 0161 quint32 StreamRestore::deviceIndex() const 0162 { 0163 return PA_INVALID_INDEX; 0164 } 0165 0166 void StreamRestore::setDeviceIndex(quint32 deviceIndex) 0167 { 0168 Q_UNUSED(deviceIndex); 0169 qCWarning(PLASMAPA) << "Not implemented"; 0170 } 0171 0172 void StreamRestore::writeChanges(const pa_cvolume &volume, bool muted, const QString &device) 0173 { 0174 const QByteArray nameData = m_name.toUtf8(); 0175 const QByteArray deviceData = device.toUtf8(); 0176 0177 pa_ext_stream_restore_info info; 0178 info.name = nameData.constData(); 0179 info.channel_map = m_channelMap; 0180 info.volume = volume; 0181 info.device = deviceData.isEmpty() ? nullptr : deviceData.constData(); 0182 info.mute = muted; 0183 0184 // If no channel exists force one. We need one to be able to control the volume 0185 // See https://bugs.kde.org/show_bug.cgi?id=407397 0186 if (info.channel_map.channels == 0) { 0187 info.channel_map.channels = 1; 0188 info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO; 0189 } 0190 0191 m_cache.valid = true; 0192 m_cache.volume = volume; 0193 m_cache.muted = muted; 0194 m_cache.device = device; 0195 0196 context()->streamRestoreWrite(&info); 0197 } 0198 0199 } // QPulseAudio