Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpulsehelpers.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
7
8Q_LOGGING_CATEGORY(qLcPulseAudioOut, "qt.multimedia.pulseaudio.output")
9Q_LOGGING_CATEGORY(qLcPulseAudioIn, "qt.multimedia.pulseaudio.input")
10Q_LOGGING_CATEGORY(qLcPulseAudioEngine, "qt.multimedia.pulseaudio.engine")
11
12namespace QPulseAudioInternal
13{
14pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
15{
16 pa_sample_spec spec;
17
18 spec.rate = format.sampleRate();
19 spec.channels = format.channelCount();
20 spec.format = PA_SAMPLE_INVALID;
21 const bool isBigEndian = QSysInfo::ByteOrder == QSysInfo::BigEndian;
22
24 spec.format = PA_SAMPLE_U8;
25 } else if (format.sampleFormat() == QAudioFormat::Int16) {
26 spec.format = isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
27 } else if (format.sampleFormat() == QAudioFormat::Int32) {
28 spec.format = isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
29 } else if (format.sampleFormat() == QAudioFormat::Float) {
30 spec.format = isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
31 }
32
33 return spec;
34}
35
36pa_channel_map channelMapForAudioFormat(const QAudioFormat &format)
37{
38 pa_channel_map map;
39 map.channels = 0;
40
41 auto config = format.channelConfig();
42 if (config == QAudioFormat::ChannelConfigUnknown)
43 config = QAudioFormat::defaultChannelConfigForChannelCount(format.channelCount());
44
45 if (config == QAudioFormat::ChannelConfigMono) {
46 map.channels = 1;
47 map.map[0] = PA_CHANNEL_POSITION_MONO;
48 } else {
49 if (config & QAudioFormat::channelConfig(QAudioFormat::FrontLeft))
50 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
51 if (config & QAudioFormat::channelConfig(QAudioFormat::FrontRight))
52 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
53 if (config & QAudioFormat::channelConfig(QAudioFormat::FrontCenter))
54 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
55 if (config & QAudioFormat::channelConfig(QAudioFormat::LFE))
56 map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
57 if (config & QAudioFormat::channelConfig(QAudioFormat::BackLeft))
58 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
59 if (config & QAudioFormat::channelConfig(QAudioFormat::BackRight))
60 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
61 if (config & QAudioFormat::channelConfig(QAudioFormat::FrontLeftOfCenter))
62 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
63 if (config & QAudioFormat::channelConfig(QAudioFormat::FrontRightOfCenter))
64 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
65 if (config & QAudioFormat::channelConfig(QAudioFormat::BackCenter))
66 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
67 if (config & QAudioFormat::channelConfig(QAudioFormat::LFE2))
68 map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
69 if (config & QAudioFormat::channelConfig(QAudioFormat::SideLeft))
70 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
71 if (config & QAudioFormat::channelConfig(QAudioFormat::SideRight))
72 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
73 if (config & QAudioFormat::channelConfig(QAudioFormat::TopFrontLeft))
74 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
75 if (config & QAudioFormat::channelConfig(QAudioFormat::TopFrontRight))
76 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
77 if (config & QAudioFormat::channelConfig(QAudioFormat::TopFrontCenter))
78 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
79 if (config & QAudioFormat::channelConfig(QAudioFormat::TopCenter))
80 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_CENTER;
81 if (config & QAudioFormat::channelConfig(QAudioFormat::TopBackLeft))
82 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
83 if (config & QAudioFormat::channelConfig(QAudioFormat::TopBackRight))
84 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
85 if (config & QAudioFormat::channelConfig(QAudioFormat::TopSideLeft))
86 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0;
87 if (config & QAudioFormat::channelConfig(QAudioFormat::TopSideRight))
88 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX1;
89 if (config & QAudioFormat::channelConfig(QAudioFormat::TopBackCenter))
90 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
91 if (config & QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter))
92 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX2;
93 if (config & QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft))
94 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX3;
95 if (config & QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight))
96 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX4;
97 }
98
99 Q_ASSERT(qPopulationCount(config) == map.channels);
100 return map;
101}
102
104{
105 quint32 config = 0;
106 for (int i = 0; i < map.channels; ++i) {
107 switch (map.map[i]) {
108 case PA_CHANNEL_POSITION_MONO:
109 case PA_CHANNEL_POSITION_FRONT_CENTER:
110 config |= QAudioFormat::channelConfig(QAudioFormat::FrontCenter);
111 break;
112 case PA_CHANNEL_POSITION_FRONT_LEFT:
113 config |= QAudioFormat::channelConfig(QAudioFormat::FrontLeft);
114 break;
115 case PA_CHANNEL_POSITION_FRONT_RIGHT:
116 config |= QAudioFormat::channelConfig(QAudioFormat::FrontRight);
117 break;
118 case PA_CHANNEL_POSITION_REAR_CENTER:
119 config |= QAudioFormat::channelConfig(QAudioFormat::BackCenter);
120 break;
121 case PA_CHANNEL_POSITION_REAR_LEFT:
122 config |= QAudioFormat::channelConfig(QAudioFormat::BackLeft);
123 break;
124 case PA_CHANNEL_POSITION_REAR_RIGHT:
125 config |= QAudioFormat::channelConfig(QAudioFormat::BackRight);
126 break;
127 case PA_CHANNEL_POSITION_LFE:
128 config |= QAudioFormat::channelConfig(QAudioFormat::LFE);
129 break;
130 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
131 config |= QAudioFormat::channelConfig(QAudioFormat::FrontLeftOfCenter);
132 break;
133 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
134 config |= QAudioFormat::channelConfig(QAudioFormat::FrontRightOfCenter);
135 break;
136 case PA_CHANNEL_POSITION_SIDE_LEFT:
137 config |= QAudioFormat::channelConfig(QAudioFormat::SideLeft);
138 break;
139 case PA_CHANNEL_POSITION_SIDE_RIGHT:
140 config |= QAudioFormat::channelConfig(QAudioFormat::SideRight);
141 break;
142
143 case PA_CHANNEL_POSITION_TOP_CENTER:
144 config |= QAudioFormat::channelConfig(QAudioFormat::TopCenter);
145 break;
146 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
147 config |= QAudioFormat::channelConfig(QAudioFormat::TopFrontLeft);
148 break;
149 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
150 config |= QAudioFormat::channelConfig(QAudioFormat::TopFrontRight);
151 break;
152 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
153 config |= QAudioFormat::channelConfig(QAudioFormat::TopFrontCenter);
154 break;
155 case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
156 config |= QAudioFormat::channelConfig(QAudioFormat::TopBackLeft);
157 break;
158 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
159 config |= QAudioFormat::channelConfig(QAudioFormat::TopBackRight);
160 break;
161 case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
162 config |= QAudioFormat::channelConfig(QAudioFormat::TopBackCenter);
163 break;
164 default:
165 break;
166 }
167 }
168 return QAudioFormat::ChannelConfig(config);
169}
170
171QAudioFormat sampleSpecToAudioFormat(const pa_sample_spec &spec)
172{
173 QAudioFormat format;
174
175 format.setSampleRate(spec.rate);
176 format.setChannelCount(spec.channels);
177 QAudioFormat::SampleFormat sampleFormat;
178 switch (spec.format) {
179 case PA_SAMPLE_U8:
180 sampleFormat = QAudioFormat::UInt8;
181 break;
182 case PA_SAMPLE_S16LE:
183 case PA_SAMPLE_S16BE:
184 sampleFormat = QAudioFormat::Int16;
185 break;
186 case PA_SAMPLE_FLOAT32LE:
187 case PA_SAMPLE_FLOAT32BE:
188 sampleFormat = QAudioFormat::Float;
189 break;
190 case PA_SAMPLE_S32LE:
191 case PA_SAMPLE_S32BE:
192 sampleFormat = QAudioFormat::Int32;
193 break;
194 default:
195 return {};
196 }
197
198 format.setSampleFormat(sampleFormat);
199 return format;
200}
201
202QUtf8StringView currentError(const pa_context *context)
203{
204 return pa_strerror(pa_context_errno(context));
205}
206
207QUtf8StringView currentError(const pa_stream *stream)
208{
209 return currentError(pa_stream_get_context(stream));
210}
211
212PAOperationHandle streamCork(const PAStreamHandle &stream, bool corkStream)
213{
214 return PAOperationHandle{
215 pa_stream_cork(stream.get(), corkStream ? 1 : 0, nullptr, nullptr),
216 PAOperationHandle::HasRef,
217 };
218}
219
220} // namespace QPulseAudioInternal
221
222static QLatin1StringView stateToQStringView(pa_stream_state_t state)
223{
224 using namespace Qt::StringLiterals;
225 switch (state)
226 {
227 case PA_STREAM_UNCONNECTED: return "Unconnected"_L1;
228 case PA_STREAM_CREATING: return "Creating"_L1;
229 case PA_STREAM_READY: return "Ready"_L1;
230 case PA_STREAM_FAILED: return "Failed"_L1;
231 case PA_STREAM_TERMINATED: return "Terminated"_L1;
232 default: Q_UNREACHABLE_RETURN("Unknown stream state"_L1);
233 }
234}
235
236static QLatin1StringView sampleFormatToQStringView(pa_sample_format format)
237{
238 using namespace Qt::StringLiterals;
239 switch (format)
240 {
241 case PA_SAMPLE_U8: return "Unsigned 8 Bit PCM."_L1;
242 case PA_SAMPLE_ALAW: return "8 Bit a-Law "_L1;
243 case PA_SAMPLE_ULAW: return "8 Bit mu-Law"_L1;
244 case PA_SAMPLE_S16LE: return "Signed 16 Bit PCM, little endian (PC)."_L1;
245 case PA_SAMPLE_S16BE: return "Signed 16 Bit PCM, big endian."_L1;
246 case PA_SAMPLE_FLOAT32LE: return "32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0"_L1;
247 case PA_SAMPLE_FLOAT32BE: return "32 Bit IEEE floating point, big endian, range -1.0 to 1.0"_L1;
248 case PA_SAMPLE_S32LE: return "Signed 32 Bit PCM, little endian (PC)."_L1;
249 case PA_SAMPLE_S32BE: return "Signed 32 Bit PCM, big endian."_L1;
250 case PA_SAMPLE_S24LE: return "Signed 24 Bit PCM packed, little endian (PC)."_L1;
251 case PA_SAMPLE_S24BE: return "Signed 24 Bit PCM packed, big endian."_L1;
252 case PA_SAMPLE_S24_32LE: return "Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC)."_L1;
253 case PA_SAMPLE_S24_32BE: return "Signed 24 Bit PCM in LSB of 32 Bit words, big endian."_L1;
254 case PA_SAMPLE_MAX: return "Upper limit of valid sample types."_L1;
255 case PA_SAMPLE_INVALID: return "Invalid sample format"_L1;
256 default: Q_UNREACHABLE_RETURN("Unknown sample format"_L1);
257 }
258}
259
260static QLatin1StringView stateToQStringView(pa_context_state_t state)
261{
262 using namespace Qt::StringLiterals;
263 switch (state)
264 {
265 case PA_CONTEXT_UNCONNECTED: return "Unconnected"_L1;
266 case PA_CONTEXT_CONNECTING: return "Connecting"_L1;
267 case PA_CONTEXT_AUTHORIZING: return "Authorizing"_L1;
268 case PA_CONTEXT_SETTING_NAME: return "Setting Name"_L1;
269 case PA_CONTEXT_READY: return "Ready"_L1;
270 case PA_CONTEXT_FAILED: return "Failed"_L1;
271 case PA_CONTEXT_TERMINATED: return "Terminated"_L1;
272 default: Q_UNREACHABLE_RETURN("Unknown context state"_L1);
273 }
274}
275
276
277QDebug operator<<(QDebug dbg, pa_stream_state_t state)
278{
279 return dbg << stateToQStringView(state);
280}
281
282QDebug operator<<(QDebug dbg, pa_sample_format format)
283{
284 return dbg << sampleFormatToQStringView(format);
285}
286
287QDebug operator<<(QDebug dbg, pa_context_state_t state)
288{
289 return dbg << stateToQStringView(state);
290}
291
292QT_END_NAMESPACE
The QAudioFormat class stores audio stream parameter information.
constexpr ChannelConfig channelConfig() const noexcept
Returns the current channel configuration.
constexpr SampleFormat sampleFormat() const noexcept
Returns the current sample format.
constexpr void setChannelCount(int channelCount) noexcept
Sets the channel count to channels.
constexpr void setSampleFormat(SampleFormat f) noexcept
Sets the sample format to format.
constexpr int sampleRate() const noexcept
Returns the current sample rate in Hertz.
SampleFormat
Qt will always expect and use samples in the endianness of the host platform.
constexpr int channelCount() const noexcept
Returns the current channel count value.
constexpr void setSampleRate(int sampleRate) noexcept
Sets the sample rate to samplerate in Hertz.
QUtf8StringView currentError(const pa_context *context)
QUtf8StringView currentError(const pa_stream *stream)
pa_channel_map channelMapForAudioFormat(const QAudioFormat &format)
QAudioFormat::ChannelConfig channelConfigFromMap(const pa_channel_map &map)
QAudioFormat sampleSpecToAudioFormat(const pa_sample_spec &spec)
pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
PAOperationHandle streamCork(const PAStreamHandle &stream, bool corkStream)
static QLatin1StringView stateToQStringView(pa_stream_state_t state)
static QLatin1StringView stateToQStringView(pa_context_state_t state)
static QLatin1StringView sampleFormatToQStringView(pa_sample_format format)
QDebug operator<<(QDebug dbg, pa_sample_format format)
QDebug operator<<(QDebug dbg, pa_stream_state_t state)
QDebug operator<<(QDebug dbg, pa_context_state_t state)