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
4#include "qpulsehelpers_p.h"
5
6QT_BEGIN_NAMESPACE
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
23 if (format.sampleFormat() == QAudioFormat::UInt8) {
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(channelCount: 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(channels: QAudioFormat::FrontLeft))
50 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
51 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::FrontRight))
52 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
53 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::FrontCenter))
54 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
55 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::LFE))
56 map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
57 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::BackLeft))
58 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
59 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::BackRight))
60 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
61 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::FrontLeftOfCenter))
62 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
63 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::FrontRightOfCenter))
64 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
65 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::BackCenter))
66 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
67 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::LFE2))
68 map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
69 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::SideLeft))
70 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
71 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::SideRight))
72 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
73 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopFrontLeft))
74 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
75 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopFrontRight))
76 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
77 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopFrontCenter))
78 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
79 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopCenter))
80 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_CENTER;
81 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopBackLeft))
82 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
83 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopBackRight))
84 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
85 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopSideLeft))
86 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0;
87 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopSideRight))
88 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX1;
89 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::TopBackCenter))
90 map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
91 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::BottomFrontCenter))
92 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX2;
93 if (config & QAudioFormat::channelConfig(channels: QAudioFormat::BottomFrontLeft))
94 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX3;
95 if (config & QAudioFormat::channelConfig(channels: 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
103QAudioFormat::ChannelConfig channelConfigFromMap(const pa_channel_map &map)
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(channels: QAudioFormat::FrontCenter);
111 break;
112 case PA_CHANNEL_POSITION_FRONT_LEFT:
113 config |= QAudioFormat::channelConfig(channels: QAudioFormat::FrontLeft);
114 break;
115 case PA_CHANNEL_POSITION_FRONT_RIGHT:
116 config |= QAudioFormat::channelConfig(channels: QAudioFormat::FrontRight);
117 break;
118 case PA_CHANNEL_POSITION_REAR_CENTER:
119 config |= QAudioFormat::channelConfig(channels: QAudioFormat::BackCenter);
120 break;
121 case PA_CHANNEL_POSITION_REAR_LEFT:
122 config |= QAudioFormat::channelConfig(channels: QAudioFormat::BackLeft);
123 break;
124 case PA_CHANNEL_POSITION_REAR_RIGHT:
125 config |= QAudioFormat::channelConfig(channels: QAudioFormat::BackRight);
126 break;
127 case PA_CHANNEL_POSITION_LFE:
128 config |= QAudioFormat::channelConfig(channels: QAudioFormat::LFE);
129 break;
130 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
131 config |= QAudioFormat::channelConfig(channels: QAudioFormat::FrontLeftOfCenter);
132 break;
133 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
134 config |= QAudioFormat::channelConfig(channels: QAudioFormat::FrontRightOfCenter);
135 break;
136 case PA_CHANNEL_POSITION_SIDE_LEFT:
137 config |= QAudioFormat::channelConfig(channels: QAudioFormat::SideLeft);
138 break;
139 case PA_CHANNEL_POSITION_SIDE_RIGHT:
140 config |= QAudioFormat::channelConfig(channels: QAudioFormat::SideRight);
141 break;
142
143 case PA_CHANNEL_POSITION_TOP_CENTER:
144 config |= QAudioFormat::channelConfig(channels: QAudioFormat::TopCenter);
145 break;
146 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
147 config |= QAudioFormat::channelConfig(channels: QAudioFormat::TopFrontLeft);
148 break;
149 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
150 config |= QAudioFormat::channelConfig(channels: QAudioFormat::TopFrontRight);
151 break;
152 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
153 config |= QAudioFormat::channelConfig(channels: QAudioFormat::TopFrontCenter);
154 break;
155 case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
156 config |= QAudioFormat::channelConfig(channels: QAudioFormat::TopBackLeft);
157 break;
158 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
159 config |= QAudioFormat::channelConfig(channels: QAudioFormat::TopBackRight);
160 break;
161 case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
162 config |= QAudioFormat::channelConfig(channels: 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(error: pa_context_errno(c: context));
205}
206
207QUtf8StringView currentError(const pa_stream *stream)
208{
209 return currentError(context: pa_stream_get_context(p: stream));
210}
211
212} // namespace QPulseAudioInternal
213
214static QLatin1StringView stateToQStringView(pa_stream_state_t state)
215{
216 using namespace Qt::StringLiterals;
217 switch (state)
218 {
219 case PA_STREAM_UNCONNECTED: return "Unconnected"_L1;
220 case PA_STREAM_CREATING: return "Creating"_L1;
221 case PA_STREAM_READY: return "Ready"_L1;
222 case PA_STREAM_FAILED: return "Failed"_L1;
223 case PA_STREAM_TERMINATED: return "Terminated"_L1;
224 default: Q_UNREACHABLE_RETURN("Unknown stream state"_L1);
225 }
226}
227
228static QLatin1StringView sampleFormatToQStringView(pa_sample_format format)
229{
230 using namespace Qt::StringLiterals;
231 switch (format)
232 {
233 case PA_SAMPLE_U8: return "Unsigned 8 Bit PCM."_L1;
234 case PA_SAMPLE_ALAW: return "8 Bit a-Law "_L1;
235 case PA_SAMPLE_ULAW: return "8 Bit mu-Law"_L1;
236 case PA_SAMPLE_S16LE: return "Signed 16 Bit PCM, little endian (PC)."_L1;
237 case PA_SAMPLE_S16BE: return "Signed 16 Bit PCM, big endian."_L1;
238 case PA_SAMPLE_FLOAT32LE: return "32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0"_L1;
239 case PA_SAMPLE_FLOAT32BE: return "32 Bit IEEE floating point, big endian, range -1.0 to 1.0"_L1;
240 case PA_SAMPLE_S32LE: return "Signed 32 Bit PCM, little endian (PC)."_L1;
241 case PA_SAMPLE_S32BE: return "Signed 32 Bit PCM, big endian."_L1;
242 case PA_SAMPLE_S24LE: return "Signed 24 Bit PCM packed, little endian (PC)."_L1;
243 case PA_SAMPLE_S24BE: return "Signed 24 Bit PCM packed, big endian."_L1;
244 case PA_SAMPLE_S24_32LE: return "Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC)."_L1;
245 case PA_SAMPLE_S24_32BE: return "Signed 24 Bit PCM in LSB of 32 Bit words, big endian."_L1;
246 case PA_SAMPLE_MAX: return "Upper limit of valid sample types."_L1;
247 case PA_SAMPLE_INVALID: return "Invalid sample format"_L1;
248 default: Q_UNREACHABLE_RETURN("Unknown sample format"_L1);
249 }
250}
251
252static QLatin1StringView stateToQStringView(pa_context_state_t state)
253{
254 using namespace Qt::StringLiterals;
255 switch (state)
256 {
257 case PA_CONTEXT_UNCONNECTED: return "Unconnected"_L1;
258 case PA_CONTEXT_CONNECTING: return "Connecting"_L1;
259 case PA_CONTEXT_AUTHORIZING: return "Authorizing"_L1;
260 case PA_CONTEXT_SETTING_NAME: return "Setting Name"_L1;
261 case PA_CONTEXT_READY: return "Ready"_L1;
262 case PA_CONTEXT_FAILED: return "Failed"_L1;
263 case PA_CONTEXT_TERMINATED: return "Terminated"_L1;
264 default: Q_UNREACHABLE_RETURN("Unknown context state"_L1);
265 }
266}
267
268
269QDebug operator<<(QDebug dbg, pa_stream_state_t state)
270{
271 return dbg << stateToQStringView(state);
272}
273
274QDebug operator<<(QDebug dbg, pa_sample_format format)
275{
276 return dbg << sampleFormatToQStringView(format);
277}
278
279QDebug operator<<(QDebug dbg, pa_context_state_t state)
280{
281 return dbg << stateToQStringView(state);
282}
283
284QT_END_NAMESPACE
285

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtmultimedia/src/multimedia/pulseaudio/qpulsehelpers.cpp