File indexing completed on 2024-12-01 13:02:23
0001 /* 0002 SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org> 0003 SPDX-FileCopyrightText: 2018 David Rosca <nowrep@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #pragma once 0009 0010 #include <QHash> 0011 #include <QObject> 0012 #include <QSet> 0013 #include <QVector> 0014 0015 #include <pulse/ext-stream-restore.h> 0016 #include <pulse/pulseaudio.h> 0017 0018 #include "card_p.h" 0019 #include "client_p.h" 0020 #include "module_p.h" 0021 #include "sink_p.h" 0022 #include "sinkinput_p.h" 0023 #include "source_p.h" 0024 #include "sourceoutput_p.h" 0025 #include "streamrestore_p.h" 0026 0027 namespace PulseAudioQt 0028 { 0029 // Used for typedefs. 0030 class Card; 0031 class Client; 0032 class Sink; 0033 class SinkInput; 0034 class Source; 0035 class SourceOutput; 0036 class StreamRestore; 0037 class Module; 0038 0039 /** 0040 * @see MapBase 0041 * This class is nothing more than the QObject base since moc cannot handle 0042 * templates. 0043 */ 0044 class MapBaseQObject : public QObject 0045 { 0046 Q_OBJECT 0047 0048 public: 0049 virtual int count() const = 0; 0050 virtual QObject *objectAt(int index) const = 0; 0051 virtual int indexOfObject(QObject *object) const = 0; 0052 0053 Q_SIGNALS: 0054 void aboutToBeAdded(int index); 0055 void added(int index, QObject *object); 0056 void aboutToBeRemoved(int index); 0057 void removed(int index, QObject *object); 0058 }; 0059 0060 /** 0061 * Maps a specific index to a specific object pointer. 0062 * This is used to give the unique arbitrary PulseAudio index of a PulseObject a 0063 * serialized list index. Namely it enables us to translate a discrete list 0064 * index to a pulse index to an object, and any permutation thereof. 0065 */ 0066 template<typename Type, typename PAInfo> 0067 class MapBase : public MapBaseQObject 0068 { 0069 public: 0070 virtual ~MapBase() 0071 { 0072 } 0073 0074 const QVector<Type *> &data() const 0075 { 0076 return m_data; 0077 } 0078 0079 int count() const override 0080 { 0081 return m_data.count(); 0082 } 0083 0084 int indexOfObject(QObject *object) const override 0085 { 0086 return m_data.indexOf(static_cast<Type *>(object)); 0087 } 0088 0089 QObject *objectAt(int index) const override 0090 { 0091 return m_data.at(index); 0092 } 0093 0094 void reset() 0095 { 0096 while (!m_hash.isEmpty()) { 0097 removeEntry(m_data.at(m_data.count() - 1)->index()); 0098 } 0099 m_pendingRemovals.clear(); 0100 } 0101 0102 void insert(Type *object) 0103 { 0104 Q_ASSERT(!m_data.contains(object)); 0105 0106 const int modelIndex = m_data.count(); 0107 0108 Q_EMIT aboutToBeAdded(modelIndex); 0109 m_data.append(object); 0110 m_hash[object->index()] = object; 0111 Q_EMIT added(modelIndex, object); 0112 } 0113 0114 // Context is passed in as parent because context needs to include the maps 0115 // so we'd cause a circular dep if we were to try to use the instance here. 0116 // Plus that's weird separation anyway. 0117 void updateEntry(const PAInfo *info, QObject *parent) 0118 { 0119 Q_ASSERT(info); 0120 0121 if (m_pendingRemovals.remove(info->index)) { 0122 // Was already removed again. 0123 return; 0124 } 0125 0126 auto *obj = m_hash.value(info->index); 0127 if (!obj) { 0128 obj = new Type(parent); 0129 obj->d->update(info); 0130 insert(obj); 0131 } else { 0132 obj->d->update(info); 0133 } 0134 } 0135 0136 void removeEntry(quint32 index) 0137 { 0138 if (!m_hash.contains(index)) { 0139 m_pendingRemovals.insert(index); 0140 } else { 0141 const int modelIndex = m_data.indexOf(m_hash.value(index)); 0142 Q_EMIT aboutToBeRemoved(modelIndex); 0143 m_data.removeAt(modelIndex); 0144 auto object = m_hash.take(index); 0145 Q_EMIT removed(modelIndex, object); 0146 delete object; 0147 } 0148 } 0149 0150 protected: 0151 QVector<Type *> m_data; 0152 QHash<quint32, Type *> m_hash; 0153 QSet<quint32> m_pendingRemovals; 0154 }; 0155 0156 typedef MapBase<Card, pa_card_info> CardMap; 0157 typedef MapBase<Client, pa_client_info> ClientMap; 0158 typedef MapBase<SinkInput, pa_sink_input_info> SinkInputMap; 0159 typedef MapBase<Sink, pa_sink_info> SinkMap; 0160 typedef MapBase<Source, pa_source_info> SourceMap; 0161 typedef MapBase<SourceOutput, pa_source_output_info> SourceOutputMap; 0162 typedef MapBase<StreamRestore, pa_ext_stream_restore_info> StreamRestoreMap; 0163 typedef MapBase<Module, pa_module_info> ModuleMap; 0164 0165 } // PulseAudioQt