File indexing completed on 2024-09-08 10:56:38
0001 /* 0002 SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #ifndef CONTEXT_H 0008 #define CONTEXT_H 0009 0010 #include <QMutex> 0011 #include <QObject> 0012 #include <QSet> 0013 0014 #include <pulse/ext-stream-restore.h> 0015 #include <pulse/glib-mainloop.h> 0016 #include <pulse/mainloop.h> 0017 #include <pulse/pulseaudio.h> 0018 0019 #include "maps.h" 0020 #include "operation.h" 0021 0022 namespace QPulseAudio 0023 { 0024 class Server; 0025 0026 class Context : public QObject 0027 { 0028 Q_OBJECT 0029 public: 0030 explicit Context(QObject *parent = nullptr); 0031 ~Context() override; 0032 0033 static Context *instance(); 0034 0035 static const qint64 NormalVolume; 0036 static const qint64 MinimalVolume; 0037 static const qint64 MaximalVolume; 0038 0039 void ref(); 0040 void unref(); 0041 0042 bool isValid() 0043 { 0044 return m_context && m_mainloop; 0045 } 0046 0047 pa_context *context() const 0048 { 0049 return m_context; 0050 } 0051 0052 const SinkMap &sinks() const 0053 { 0054 return m_sinks; 0055 } 0056 const SinkInputMap &sinkInputs() const 0057 { 0058 return m_sinkInputs; 0059 } 0060 const SourceMap &sources() const 0061 { 0062 return m_sources; 0063 } 0064 const SourceOutputMap &sourceOutputs() const 0065 { 0066 return m_sourceOutputs; 0067 } 0068 const ClientMap &clients() const 0069 { 0070 return m_clients; 0071 } 0072 const CardMap &cards() const 0073 { 0074 return m_cards; 0075 } 0076 const ModuleMap &modules() const 0077 { 0078 return m_modules; 0079 } 0080 const StreamRestoreMap &streamRestores() const 0081 { 0082 return m_streamRestores; 0083 } 0084 Server *server() const 0085 { 0086 return m_server; 0087 } 0088 QString newDefaultSink() const 0089 { 0090 return m_newDefaultSink; 0091 } 0092 QString newDefaultSource() const 0093 { 0094 return m_newDefaultSource; 0095 } 0096 0097 void subscribeCallback(pa_context *context, pa_subscription_event_type_t type, uint32_t index); 0098 void contextStateCallback(pa_context *context); 0099 0100 void sinkCallback(const pa_sink_info *info); 0101 void sinkInputCallback(const pa_sink_input_info *info); 0102 void sourceCallback(const pa_source_info *info); 0103 void sourceOutputCallback(const pa_source_output_info *info); 0104 void clientCallback(const pa_client_info *info); 0105 void cardCallback(const pa_card_info *info); 0106 void moduleCallback(const pa_module_info *info); 0107 void streamRestoreCallback(const pa_ext_stream_restore_info *info); 0108 void serverCallback(const pa_server_info *info); 0109 0110 void setCardProfile(quint32 index, const QString &profile); 0111 void setDefaultSink(const QString &name); 0112 void setDefaultSource(const QString &name); 0113 void streamRestoreWrite(const pa_ext_stream_restore_info *info); 0114 0115 static void setApplicationId(const QString &applicationId); 0116 0117 template<typename PAFunction> 0118 void setGenericVolume(quint32 index, int channel, qint64 newVolume, pa_cvolume cVolume, PAFunction pa_set_volume) 0119 { 0120 if (!m_context) { 0121 return; 0122 } 0123 newVolume = qBound<qint64>(0, newVolume, PA_VOLUME_MAX); 0124 pa_cvolume newCVolume = cVolume; 0125 if (channel == -1) { // -1 all channels 0126 const qint64 orig = pa_cvolume_max(&cVolume); 0127 const qint64 diff = newVolume - orig; 0128 for (int i = 0; i < newCVolume.channels; ++i) { 0129 const qint64 channel = newCVolume.values[i]; 0130 const qint64 channelDiff = orig == 0 ? diff : diff * channel / orig; 0131 newCVolume.values[i] = qBound<qint64>(0, newCVolume.values[i] + channelDiff, PA_VOLUME_MAX); 0132 } 0133 } else { 0134 Q_ASSERT(newCVolume.channels > channel); 0135 newCVolume.values[channel] = newVolume; 0136 } 0137 if (!PAOperation(pa_set_volume(m_context, index, &newCVolume, nullptr, nullptr))) { 0138 qCWarning(PLASMAPA) << "pa_set_volume failed"; 0139 return; 0140 } 0141 } 0142 0143 template<typename PAFunction> 0144 void setGenericVolumes(quint32 index, QVector<qint64> channelVolumes, pa_cvolume cVolume, PAFunction pa_set_volume) 0145 { 0146 if (!m_context) { 0147 return; 0148 } 0149 Q_ASSERT(channelVolumes.count() == cVolume.channels); 0150 0151 pa_cvolume newCVolume = cVolume; 0152 for (int i = 0; i < channelVolumes.count(); ++i) { 0153 newCVolume.values[i] = qBound<qint64>(0, channelVolumes.at(i), PA_VOLUME_MAX); 0154 } 0155 0156 if (!PAOperation(pa_set_volume(m_context, index, &newCVolume, nullptr, nullptr))) { 0157 qCWarning(PLASMAPA) << "pa_set_volume failed"; 0158 return; 0159 } 0160 } 0161 0162 template<typename PAFunction> 0163 void setGenericMute(quint32 index, bool mute, PAFunction pa_set_mute) 0164 { 0165 if (!m_context) { 0166 return; 0167 } 0168 if (!PAOperation(pa_set_mute(m_context, index, mute, nullptr, nullptr))) { 0169 qCWarning(PLASMAPA) << "pa_set_mute failed"; 0170 return; 0171 } 0172 } 0173 0174 template<typename PAFunction> 0175 void setGenericPort(quint32 index, const QString &portName, PAFunction pa_set_port) 0176 { 0177 if (!m_context) { 0178 return; 0179 } 0180 if (!PAOperation(pa_set_port(m_context, index, portName.toUtf8().constData(), nullptr, nullptr))) { 0181 qCWarning(PLASMAPA) << "pa_set_port failed"; 0182 return; 0183 } 0184 } 0185 0186 template<typename PAFunction> 0187 void setGenericDeviceForStream(quint32 streamIndex, quint32 deviceIndex, PAFunction pa_move_stream_to_device) 0188 { 0189 if (!m_context) { 0190 return; 0191 } 0192 if (!PAOperation(pa_move_stream_to_device(m_context, streamIndex, deviceIndex, nullptr, nullptr))) { 0193 qCWarning(PLASMAPA) << "pa_move_stream_to_device failed"; 0194 return; 0195 } 0196 } 0197 0198 private: 0199 void connectToDaemon(); 0200 void reset(); 0201 0202 // Don't forget to add things to reset(). 0203 SinkMap m_sinks; 0204 SinkInputMap m_sinkInputs; 0205 SourceMap m_sources; 0206 SourceOutputMap m_sourceOutputs; 0207 ClientMap m_clients; 0208 CardMap m_cards; 0209 ModuleMap m_modules; 0210 StreamRestoreMap m_streamRestores; 0211 Server *m_server; 0212 0213 pa_context *m_context; 0214 pa_glib_mainloop *m_mainloop; 0215 0216 QString m_newDefaultSink; 0217 QString m_newDefaultSource; 0218 0219 int m_references; 0220 static Context *s_context; 0221 static QString s_applicationId; 0222 }; 0223 0224 } // QPulseAudio 0225 0226 #endif // CONTEXT_H